From 852558eb0651d1b33dd6e5e0e9a9f169d315a3bd Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 4 Sep 2005 23:05:58 +0000 Subject: [PATCH] replace slow entity parsing code --- stepmania/src/XmlFile.cpp | 181 ++++++++++---------------------------- stepmania/src/XmlFile.h | 28 +----- 2 files changed, 48 insertions(+), 161 deletions(-) diff --git a/stepmania/src/XmlFile.cpp b/stepmania/src/XmlFile.cpp index 539d079a06..1f99eb3e4e 100644 --- a/stepmania/src/XmlFile.cpp +++ b/stepmania/src/XmlFile.cpp @@ -22,15 +22,40 @@ static const char chXMLExclamation = '!'; static const char chXMLDash = '-'; -static const XENTITY x_EntityTable[] = { - { '&', "&", 5 } , - { '\"', """, 6 } , - { '\'', "'", 6 } , - { '<', "<", 4 } , - { '>', ">", 4 } +static map g_mapEntitiesToChars; +static map g_mapCharsToEntities; + +static void InitEntities() +{ + if( !g_mapEntitiesToChars.empty() ) + return; + + struct Entity + { + char c; + const char *pEntity; + } + static const EntityTable[] = + { + { '&', "amp", }, + { '\"', "quot", }, + { '\'', "apos", }, + { '<', "lt", }, + { '>', "gt", } }; -XENTITYS entityDefault(x_EntityTable, sizeof(x_EntityTable)/sizeof(x_EntityTable[0]) ); + for( unsigned i = 0; i < ARRAYSIZE(EntityTable); ++i ) + { + const Entity &ent = EntityTable[i]; + g_mapEntitiesToChars[ent.pEntity] = CString(1, ent.c); + g_mapCharsToEntities[ent.c] = ent.pEntity; + } +} + +struct RunInitEntities +{ + RunInitEntities() { InitEntities(); } +} static g_RunInitEntities; // skip spaces static char* tcsskip( const char* psz ) @@ -249,8 +274,8 @@ const char* XNode::LoadAttributes( const char* xml, PARSEINFO *pi /*= &piDefault SetString( xml, pEnd, &attr->m_sValue, trim, escape ); xml = pEnd; // ATTRVALUE - if( pi->entity_value && pi->entitys ) - attr->m_sValue = pi->entitys->Ref2Entity(attr->m_sValue); + if( pi->entity_value ) + ReplaceEntityText( attr->m_sValue, g_mapEntitiesToChars ); if( quote == '"' || quote == '\'' ) xml++; @@ -383,8 +408,8 @@ const char* XNode::Load( const char* xml, PARSEINFO *pi /*= &piDefault*/ ) xml = pEnd; // TEXTVALUE reference - if( pi->entity_value && pi->entitys ) - m_sValue = pi->entitys->Ref2Entity(m_sValue); + if( pi->entity_value ) + ReplaceEntityText( m_sValue, g_mapEntitiesToChars ); } // generate child nodes @@ -477,8 +502,8 @@ const char* XNode::Load( const char* xml, PARSEINFO *pi /*= &piDefault*/ ) xml = pEnd; //TEXTVALUE - if( pi->entity_value && pi->entitys ) - m_sValue = pi->entitys->Ref2Entity(m_sValue); + if( pi->entity_value ) + ReplaceEntityText( m_sValue, g_mapEntitiesToChars ); } } } @@ -490,7 +515,10 @@ const char* XNode::Load( const char* xml, PARSEINFO *pi /*= &piDefault*/ ) // Return : converted plain string bool XAttr::GetXML( RageFileBasic &f, DISP_OPT *opt ) const { - return f.Write(m_sName + "='" + (opt && opt->reference_value && opt->entitys ? opt->entitys->Entity2Ref(m_sValue) : m_sValue) + "' ") != -1; + CString s(m_sValue); + if( opt && opt->reference_value ) + ReplaceEntityText( s, g_mapCharsToEntities ); + return f.Write(m_sName + "='" + s + "' ") != -1; } // Desc : convert plain xml text from parsed xml node @@ -542,7 +570,7 @@ bool XNode::GetXML( RageFileBasic &f, DISP_OPT *opt ) const return false; // Text Value - if( m_sValue != ("") ) + if( !m_sValue.empty() ) { if( opt && opt->newline && !m_childs.empty() ) { @@ -554,7 +582,10 @@ bool XNode::GetXML( RageFileBasic &f, DISP_OPT *opt ) const if( f.Write("\t") == -1 ) return false; } - if( f.Write((opt && opt->reference_value && opt->entitys ? opt->entitys->Entity2Ref(m_sValue) : m_sValue)) == -1 ) + CString s( m_sValue ); + if( opt && opt->reference_value ) + ReplaceEntityText( s, g_mapCharsToEntities ); + if( f.Write(s) == -1 ) return false; } @@ -729,124 +760,6 @@ void XNode::SetAttrValue( const CString &sName, const CString &sValue ) } -XENTITYS::XENTITYS( const XENTITY *entities, int count ) -{ - for( int i = 0; i < count; i++) - push_back( entities[i] ); -} - -const XENTITY *XENTITYS::GetEntity( char entity ) const -{ - for( unsigned i = 0 ; i < size(); i ++ ) - { - if( at(i).entity == entity ) - return &at(i); - } - return NULL; -} - -const XENTITY *XENTITYS::GetEntity( const char* entity ) const -{ - for( unsigned i = 0 ; i < size(); i ++ ) - { - const char* ref = at(i).ref; - const char* ps = entity; - while( ref && *ref ) - if( *ref++ != *ps++ ) - break; - if( ref && !*ref ) // found! - return &at(i); - } - return NULL; -} - -int XENTITYS::GetEntityCount( const char* str ) const -{ - int nCount = 0; - while( str && *str ) - if( GetEntity(*str++) ) - ++nCount; - return nCount; -} - -int XENTITYS::Ref2Entity( const char* pes, char* str, int len ) const -{ - char* ps = str; - char* ps_end = ps+len; - while( pes && *pes && ps < ps_end ) - { - const XENTITY *ent = GetEntity( pes ); - if( ent ) - { - // copy entity meanning char - *ps = ent->entity; - pes += ent->ref_len; - } - else - *ps = *pes++; // default character copy - ps++; - } - *ps = '\0'; - - // total copied characters - return ps-str; -} - -int XENTITYS::Entity2Ref( const char* ps, char* estr, int estrlen ) const -{ - char* pes = estr; - char* pes_end = pes+estrlen; - while( ps && *ps && pes < pes_end ) - { - const XENTITY *ent = GetEntity( *ps ); - if( ent ) - { - // copy entity string - const char* ref = ent->ref; - while( ref && *ref ) - *pes++ = *ref++; - } - else - *pes++ = *ps; // default character copy - ps++; - } - *pes = '\0'; - - // total copied characters - return pes-estr; -} - -CString XENTITYS::Ref2Entity( const char* estr ) const -{ - CString es; - if( estr ) - { - int len = strlen(estr); - char* szTemp = new char[len+1]; - int iLen = Ref2Entity( estr, szTemp, len ); - es.assign( szTemp, iLen ); - delete [] szTemp; - } - return es; -} - -CString XENTITYS::Entity2Ref( const char* str ) const -{ - CString s; - if( str ) - { - int nEntityCount = GetEntityCount(str); - if( nEntityCount == 0 ) - return CString(str); - int len = strlen(str) + nEntityCount*10; - char* szTemp = new char[len+1]; - int iLen = Entity2Ref( str, szTemp, len ); - s.assign( szTemp, iLen ); - delete [] szTemp; - } - return s; -} - bool XNode::LoadFromFile( const CString &sFile ) { RageFile f; diff --git a/stepmania/src/XmlFile.h b/stepmania/src/XmlFile.h index 460d07cea0..48ac252c52 100644 --- a/stepmania/src/XmlFile.h +++ b/stepmania/src/XmlFile.h @@ -57,29 +57,6 @@ typedef multimap XNodes; ++Var##Iter, Var = Var##Iter->second ) -// Entity Encode/Decode Support -struct XENTITY -{ - char entity; // entity ( & " ' < > ) - char ref[10]; // entity reference ( & " etc ) - int ref_len; // entity reference length -}; - -struct XENTITYS : public vector -{ - const XENTITY *GetEntity( char entity ) const; - const XENTITY *GetEntity( const char* entity ) const; - int GetEntityCount( const char* str ) const; - int Ref2Entity( const char* estr, char* str, int strlen ) const; - int Entity2Ref( const char* str, char* estr, int estrlen ) const; - CString Ref2Entity( const char* estr ) const; - CString Entity2Ref( const char* str ) const; - - XENTITYS(){}; - XENTITYS( const XENTITY *entities, int count ); -}; -extern XENTITYS entityDefault; - enum PCODE { PIE_PARSE_WELL_FORMED = 0, @@ -95,7 +72,6 @@ struct PARSEINFO { bool trim_value; // [set] do trim when parse? bool entity_value; // [set] do convert from reference to entity? ( < -> < ) - XENTITYS *entitys; // [set] entity table for entity decode char escape_value; // [set] escape value (default '\\') char* xml; // [get] xml source @@ -104,7 +80,7 @@ struct PARSEINFO PCODE error_code; // [get] error code CString error_string; // [get] error string - PARSEINFO() { trim_value = true; entity_value = true; entitys = &entityDefault; xml = NULL; error_occur = false; error_pointer = NULL; error_code = PIE_PARSE_WELL_FORMED; escape_value = 0; } + PARSEINFO() { trim_value = true; entity_value = true; xml = NULL; error_occur = false; error_pointer = NULL; error_code = PIE_PARSE_WELL_FORMED; escape_value = 0; } }; // display optional environment @@ -112,7 +88,6 @@ struct DISP_OPT { bool newline; // newline when new tag bool reference_value; // do convert from entity to reference ( < -> < ) - XENTITYS *entitys; // entity table for entity encode CString stylesheet; // empty string = no stylesheet bool write_tabs; // if false, don't write tab indent characters @@ -121,7 +96,6 @@ struct DISP_OPT { newline = true; reference_value = true; - entitys = &entityDefault; stylesheet = ""; write_tabs = true; tab_base = 0;