Home | History | Annotate | Download | only in tinyxml2
      1 /*
      2 Original code by Lee Thomason (www.grinninglizard.com)
      3 
      4 This software is provided 'as-is', without any express or implied
      5 warranty. In no event will the authors be held liable for any
      6 damages arising from the use of this software.
      7 
      8 Permission is granted to anyone to use this software for any
      9 purpose, including commercial applications, and to alter it and
     10 redistribute it freely, subject to the following restrictions:
     11 
     12 1. The origin of this software must not be misrepresented; you must
     13 not claim that you wrote the original software. If you use this
     14 software in a product, an acknowledgment in the product documentation
     15 would be appreciated but is not required.
     16 
     17 2. Altered source versions must be plainly marked as such, and
     18 must not be misrepresented as being the original software.
     19 
     20 3. This notice may not be removed or altered from any source
     21 distribution.
     22 */
     23 #include "tinyxml2.h"
     24 
     25 #include <cstdio>
     26 #include <cstdlib>
     27 #include <new>
     28 #include <cstddef>
     29 
     30 #include <fcntl.h>
     31 using namespace tinyxml2;
     32 
     33 static const char LINE_FEED                = (char)0x0a;            // all line endings are normalized to LF
     34 static const char LF = LINE_FEED;
     35 static const char CARRIAGE_RETURN        = (char)0x0d;            // CR gets filtered out
     36 static const char CR = CARRIAGE_RETURN;
     37 static const char SINGLE_QUOTE            = '\'';
     38 static const char DOUBLE_QUOTE            = '\"';
     39 
     40 // Bunch of unicode info at:
     41 //        http://www.unicode.org/faq/utf_bom.html
     42 //    ef bb bf (Microsoft "lead bytes") - designates UTF-8
     43 
     44 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
     45 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
     46 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
     47 
     48 
     49 #define DELETE_NODE( node )    {            \
     50     if ( node ) {                        \
     51         MemPool* pool = node->memPool;    \
     52         node->~XMLNode();                \
     53         pool->Free( node );                \
     54     }                                    \
     55 }
     56 #define DELETE_ATTRIBUTE( attrib ) {        \
     57     if ( attrib ) {                            \
     58         MemPool* pool = attrib->memPool;    \
     59         attrib->~XMLAttribute();            \
     60         pool->Free( attrib );                \
     61     }                                        \
     62 }
     63 
     64 struct Entity {
     65     const char* pattern;
     66     int length;
     67     char value;
     68 };
     69 
     70 static const int NUM_ENTITIES = 5;
     71 static const Entity entities[NUM_ENTITIES] =
     72 {
     73     { "quot", 4,    DOUBLE_QUOTE },
     74     { "amp", 3,        '&'  },
     75     { "apos", 4,    SINGLE_QUOTE },
     76     { "lt",    2,         '<'     },
     77     { "gt",    2,        '>'     }
     78 };
     79 
     80 
     81 StrPair::~StrPair()
     82 {
     83     Reset();
     84 }
     85 
     86 
     87 void StrPair::Reset()
     88 {
     89     if ( flags & NEEDS_DELETE ) {
     90         delete [] start;
     91     }
     92     flags = 0;
     93     start = 0;
     94     end = 0;
     95 }
     96 
     97 
     98 void StrPair::SetStr( const char* str, int flags )
     99 {
    100     Reset();
    101     size_t len = strlen( str );
    102     start = new char[ len+1 ];
    103     memcpy( start, str, len+1 );
    104     end = start + len;
    105     this->flags = flags | NEEDS_DELETE;
    106 }
    107 
    108 
    109 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
    110 {
    111     TIXMLASSERT( endTag && *endTag );
    112 
    113     char* start = p;    // fixme: hides a member
    114     char  endChar = *endTag;
    115     size_t length = strlen( endTag );
    116 
    117     // Inner loop of text parsing.
    118     while ( *p ) {
    119         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
    120             Set( start, p, strFlags );
    121             return p + length;
    122         }
    123         ++p;
    124     }
    125     return 0;
    126 }
    127 
    128 
    129 char* StrPair::ParseName( char* p )
    130 {
    131     char* start = p;
    132 
    133     if ( !start || !(*start) ) {
    134         return 0;
    135     }
    136 
    137     if ( !XMLUtil::IsAlpha( *p ) ) {
    138         return 0;
    139     }
    140 
    141     while( *p && (
    142                XMLUtil::IsAlphaNum( (unsigned char) *p )
    143             || *p == '_'
    144             || *p == '-'
    145             || *p == '.'
    146             || *p == ':' ))
    147     {
    148         ++p;
    149     }
    150 
    151     if ( p > start ) {
    152         Set( start, p, 0 );
    153         return p;
    154     }
    155     return 0;
    156 }
    157 
    158 
    159 
    160 const char* StrPair::GetStr()
    161 {
    162     if ( flags & NEEDS_FLUSH ) {
    163         *end = 0;
    164         flags ^= NEEDS_FLUSH;
    165 
    166         if ( flags ) {
    167             char* p = start;    // the read pointer
    168             char* q = start;    // the write pointer
    169 
    170             while( p < end ) {
    171                 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
    172                     // CR-LF pair becomes LF
    173                     // CR alone becomes LF
    174                     // LF-CR becomes LF
    175                     if ( *(p+1) == LF ) {
    176                         p += 2;
    177                     }
    178                     else {
    179                         ++p;
    180                     }
    181                     *q++ = LF;
    182                 }
    183                 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
    184                     if ( *(p+1) == CR ) {
    185                         p += 2;
    186                     }
    187                     else {
    188                         ++p;
    189                     }
    190                     *q++ = LF;
    191                 }
    192                 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
    193                     // Entities handled by tinyXML2:
    194                     // - special entities in the entity table [in/out]
    195                     // - numeric character reference [in]
    196                     //   &#20013; or &#x4e2d;
    197 
    198                     if ( *(p+1) == '#' ) {
    199                         char buf[10] = { 0 };
    200                         int len;
    201                         p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
    202                         for( int i=0; i<len; ++i ) {
    203                             *q++ = buf[i];
    204                         }
    205                         TIXMLASSERT( q <= p );
    206                     }
    207                     else {
    208                         int i=0;
    209                         for(; i<NUM_ENTITIES; ++i ) {
    210                             if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
    211                                  && *(p+entities[i].length+1) == ';' )
    212                             {
    213                                 // Found an entity convert;
    214                                 *q = entities[i].value;
    215                                 ++q;
    216                                 p += entities[i].length + 2;
    217                                 break;
    218                             }
    219                         }
    220                         if ( i == NUM_ENTITIES ) {
    221                             // fixme: treat as error?
    222                             ++p;
    223                             ++q;
    224                         }
    225                     }
    226                 }
    227                 else {
    228                     *q = *p;
    229                     ++p;
    230                     ++q;
    231                 }
    232             }
    233             *q = 0;
    234         }
    235         flags = (flags & NEEDS_DELETE);
    236     }
    237     return start;
    238 }
    239 
    240 
    241 
    242 
    243 // --------- XMLUtil ----------- //
    244 
    245 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
    246 {
    247     *bom = false;
    248     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
    249     // Check for BOM:
    250     if (    *(pu+0) == TIXML_UTF_LEAD_0
    251          && *(pu+1) == TIXML_UTF_LEAD_1
    252          && *(pu+2) == TIXML_UTF_LEAD_2 )
    253     {
    254         *bom = true;
    255         p += 3;
    256     }
    257     return p;
    258 }
    259 
    260 
    261 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
    262 {
    263     const unsigned long BYTE_MASK = 0xBF;
    264     const unsigned long BYTE_MARK = 0x80;
    265     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
    266 
    267     if (input < 0x80)
    268         *length = 1;
    269     else if ( input < 0x800 )
    270         *length = 2;
    271     else if ( input < 0x10000 )
    272         *length = 3;
    273     else if ( input < 0x200000 )
    274         *length = 4;
    275     else
    276         { *length = 0; return; }    // This code won't covert this correctly anyway.
    277 
    278     output += *length;
    279 
    280     // Scary scary fall throughs.
    281     switch (*length)
    282     {
    283         case 4:
    284             --output;
    285             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    286             input >>= 6;
    287         case 3:
    288             --output;
    289             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    290             input >>= 6;
    291         case 2:
    292             --output;
    293             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    294             input >>= 6;
    295         case 1:
    296             --output;
    297             *output = (char)(input | FIRST_BYTE_MARK[*length]);
    298     }
    299 }
    300 
    301 
    302 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
    303 {
    304     // Presume an entity, and pull it out.
    305     *length = 0;
    306 
    307     if ( *(p+1) == '#' && *(p+2) )
    308     {
    309         unsigned long ucs = 0;
    310         ptrdiff_t delta = 0;
    311         unsigned mult = 1;
    312 
    313         if ( *(p+2) == 'x' )
    314         {
    315             // Hexadecimal.
    316             if ( !*(p+3) ) return 0;
    317 
    318             const char* q = p+3;
    319             q = strchr( q, ';' );
    320 
    321             if ( !q || !*q ) return 0;
    322 
    323             delta = q-p;
    324             --q;
    325 
    326             while ( *q != 'x' )
    327             {
    328                 if ( *q >= '0' && *q <= '9' )
    329                     ucs += mult * (*q - '0');
    330                 else if ( *q >= 'a' && *q <= 'f' )
    331                     ucs += mult * (*q - 'a' + 10);
    332                 else if ( *q >= 'A' && *q <= 'F' )
    333                     ucs += mult * (*q - 'A' + 10 );
    334                 else
    335                     return 0;
    336                 mult *= 16;
    337                 --q;
    338             }
    339         }
    340         else
    341         {
    342             // Decimal.
    343             if ( !*(p+2) ) return 0;
    344 
    345             const char* q = p+2;
    346             q = strchr( q, ';' );
    347 
    348             if ( !q || !*q ) return 0;
    349 
    350             delta = q-p;
    351             --q;
    352 
    353             while ( *q != '#' )
    354             {
    355                 if ( *q >= '0' && *q <= '9' )
    356                     ucs += mult * (*q - '0');
    357                 else
    358                     return 0;
    359                 mult *= 10;
    360                 --q;
    361             }
    362         }
    363         // convert the UCS to UTF-8
    364         ConvertUTF32ToUTF8( ucs, value, length );
    365         return p + delta + 1;
    366     }
    367     return p+1;
    368 }
    369 
    370 
    371 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
    372 {
    373     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
    374 }
    375 
    376 
    377 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
    378 {
    379     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
    380 }
    381 
    382 
    383 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
    384 {
    385     TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
    386 }
    387 
    388 
    389 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
    390 {
    391     TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
    392 }
    393 
    394 
    395 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
    396 {
    397     TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
    398 }
    399 
    400 
    401 bool XMLUtil::ToInt( const char* str, int* value )
    402 {
    403     if ( TIXML_SSCANF( str, "%d", value ) == 1 )
    404         return true;
    405     return false;
    406 }
    407 
    408 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
    409 {
    410     if ( TIXML_SSCANF( str, "%u", value ) == 1 )
    411         return true;
    412     return false;
    413 }
    414 
    415 bool XMLUtil::ToBool( const char* str, bool* value )
    416 {
    417     int ival = 0;
    418     if ( ToInt( str, &ival )) {
    419         *value = (ival==0) ? false : true;
    420         return true;
    421     }
    422     if ( StringEqual( str, "true" ) ) {
    423         *value = true;
    424         return true;
    425     }
    426     else if ( StringEqual( str, "false" ) ) {
    427         *value = false;
    428         return true;
    429     }
    430     return false;
    431 }
    432 
    433 
    434 bool XMLUtil::ToFloat( const char* str, float* value )
    435 {
    436     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
    437         return true;
    438     }
    439     return false;
    440 }
    441 
    442 bool XMLUtil::ToDouble( const char* str, double* value )
    443 {
    444     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
    445         return true;
    446     }
    447     return false;
    448 }
    449 
    450 
    451 char* XMLDocument::Identify( char* p, XMLNode** node )
    452 {
    453     XMLNode* returnNode = 0;
    454     char* start = p;
    455     p = XMLUtil::SkipWhiteSpace( p );
    456     if( !p || !*p )
    457     {
    458         return p;
    459     }
    460 
    461     // What is this thing?
    462     // - Elements start with a letter or underscore, but xml is reserved.
    463     // - Comments: <!--
    464     // - Decleration: <?
    465     // - Everthing else is unknown to tinyxml.
    466     //
    467 
    468     static const char* xmlHeader        = { "<?" };
    469     static const char* commentHeader    = { "<!--" };
    470     static const char* dtdHeader        = { "<!" };
    471     static const char* cdataHeader        = { "<![CDATA[" };
    472     static const char* elementHeader    = { "<" };    // and a header for everything else; check last.
    473 
    474     static const int xmlHeaderLen        = 2;
    475     static const int commentHeaderLen    = 4;
    476     static const int dtdHeaderLen        = 2;
    477     static const int cdataHeaderLen        = 9;
    478     static const int elementHeaderLen    = 1;
    479 
    480 #if defined(_MSC_VER)
    481 #pragma warning ( push )
    482 #pragma warning ( disable : 4127 )
    483 #endif
    484     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool
    485     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
    486 #if defined(_MSC_VER)
    487 #pragma warning (pop)
    488 #endif
    489     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
    490         returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
    491         returnNode->memPool = &commentPool;
    492         p += xmlHeaderLen;
    493     }
    494     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
    495         returnNode = new (commentPool.Alloc()) XMLComment( this );
    496         returnNode->memPool = &commentPool;
    497         p += commentHeaderLen;
    498     }
    499     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
    500         XMLText* text = new (textPool.Alloc()) XMLText( this );
    501         returnNode = text;
    502         returnNode->memPool = &textPool;
    503         p += cdataHeaderLen;
    504         text->SetCData( true );
    505     }
    506     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
    507         returnNode = new (commentPool.Alloc()) XMLUnknown( this );
    508         returnNode->memPool = &commentPool;
    509         p += dtdHeaderLen;
    510     }
    511     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
    512         returnNode = new (elementPool.Alloc()) XMLElement( this );
    513         returnNode->memPool = &elementPool;
    514         p += elementHeaderLen;
    515     }
    516     else {
    517         returnNode = new (textPool.Alloc()) XMLText( this );
    518         returnNode->memPool = &textPool;
    519         p = start;    // Back it up, all the text counts.
    520     }
    521 
    522     *node = returnNode;
    523     return p;
    524 }
    525 
    526 
    527 bool XMLDocument::Accept( XMLVisitor* visitor ) const
    528 {
    529     if ( visitor->VisitEnter( *this ) )
    530     {
    531         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
    532         {
    533             if ( !node->Accept( visitor ) )
    534                 break;
    535         }
    536     }
    537     return visitor->VisitExit( *this );
    538 }
    539 
    540 
    541 // --------- XMLNode ----------- //
    542 
    543 XMLNode::XMLNode( XMLDocument* doc ) :
    544     document( doc ),
    545     parent( 0 ),
    546     firstChild( 0 ), lastChild( 0 ),
    547     prev( 0 ), next( 0 )
    548 {
    549 }
    550 
    551 
    552 XMLNode::~XMLNode()
    553 {
    554     DeleteChildren();
    555     if ( parent ) {
    556         parent->Unlink( this );
    557     }
    558 }
    559 
    560 
    561 void XMLNode::SetValue( const char* str, bool staticMem )
    562 {
    563     if ( staticMem )
    564         value.SetInternedStr( str );
    565     else
    566         value.SetStr( str );
    567 }
    568 
    569 
    570 void XMLNode::DeleteChildren()
    571 {
    572     while( firstChild ) {
    573         XMLNode* node = firstChild;
    574         Unlink( node );
    575 
    576         DELETE_NODE( node );
    577     }
    578     firstChild = lastChild = 0;
    579 }
    580 
    581 
    582 void XMLNode::Unlink( XMLNode* child )
    583 {
    584     TIXMLASSERT( child->parent == this );
    585     if ( child == firstChild )
    586         firstChild = firstChild->next;
    587     if ( child == lastChild )
    588         lastChild = lastChild->prev;
    589 
    590     if ( child->prev ) {
    591         child->prev->next = child->next;
    592     }
    593     if ( child->next ) {
    594         child->next->prev = child->prev;
    595     }
    596     child->parent = 0;
    597 }
    598 
    599 
    600 void XMLNode::DeleteChild( XMLNode* node )
    601 {
    602     TIXMLASSERT( node->parent == this );
    603     DELETE_NODE( node );
    604 }
    605 
    606 
    607 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
    608 {
    609     if ( lastChild ) {
    610         TIXMLASSERT( firstChild );
    611         TIXMLASSERT( lastChild->next == 0 );
    612         lastChild->next = addThis;
    613         addThis->prev = lastChild;
    614         lastChild = addThis;
    615 
    616         addThis->next = 0;
    617     }
    618     else {
    619         TIXMLASSERT( firstChild == 0 );
    620         firstChild = lastChild = addThis;
    621 
    622         addThis->prev = 0;
    623         addThis->next = 0;
    624     }
    625     addThis->parent = this;
    626     return addThis;
    627 }
    628 
    629 
    630 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
    631 {
    632     if ( firstChild ) {
    633         TIXMLASSERT( lastChild );
    634         TIXMLASSERT( firstChild->prev == 0 );
    635 
    636         firstChild->prev = addThis;
    637         addThis->next = firstChild;
    638         firstChild = addThis;
    639 
    640         addThis->prev = 0;
    641     }
    642     else {
    643         TIXMLASSERT( lastChild == 0 );
    644         firstChild = lastChild = addThis;
    645 
    646         addThis->prev = 0;
    647         addThis->next = 0;
    648     }
    649     addThis->parent = this;
    650     return addThis;
    651 }
    652 
    653 
    654 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
    655 {
    656     TIXMLASSERT( afterThis->parent == this );
    657     if ( afterThis->parent != this )
    658         return 0;
    659 
    660     if ( afterThis->next == 0 ) {
    661         // The last node or the only node.
    662         return InsertEndChild( addThis );
    663     }
    664     addThis->prev = afterThis;
    665     addThis->next = afterThis->next;
    666     afterThis->next->prev = addThis;
    667     afterThis->next = addThis;
    668     addThis->parent = this;
    669     return addThis;
    670 }
    671 
    672 
    673 
    674 
    675 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
    676 {
    677     for( XMLNode* node=firstChild; node; node=node->next ) {
    678         XMLElement* element = node->ToElement();
    679         if ( element ) {
    680             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
    681                 return element;
    682             }
    683         }
    684     }
    685     return 0;
    686 }
    687 
    688 
    689 const XMLElement* XMLNode::LastChildElement( const char* value ) const
    690 {
    691     for( XMLNode* node=lastChild; node; node=node->prev ) {
    692         XMLElement* element = node->ToElement();
    693         if ( element ) {
    694             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
    695                 return element;
    696             }
    697         }
    698     }
    699     return 0;
    700 }
    701 
    702 
    703 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
    704 {
    705     for( XMLNode* element=this->next; element; element = element->next ) {
    706         if (    element->ToElement()
    707              && (!value || XMLUtil::StringEqual( value, element->Value() )))
    708         {
    709             return element->ToElement();
    710         }
    711     }
    712     return 0;
    713 }
    714 
    715 
    716 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
    717 {
    718     for( XMLNode* element=this->prev; element; element = element->prev ) {
    719         if (    element->ToElement()
    720              && (!value || XMLUtil::StringEqual( value, element->Value() )))
    721         {
    722             return element->ToElement();
    723         }
    724     }
    725     return 0;
    726 }
    727 
    728 
    729 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
    730 {
    731     // This is a recursive method, but thinking about it "at the current level"
    732     // it is a pretty simple flat list:
    733     //        <foo/>
    734     //        <!-- comment -->
    735     //
    736     // With a special case:
    737     //        <foo>
    738     //        </foo>
    739     //        <!-- comment -->
    740     //
    741     // Where the closing element (/foo) *must* be the next thing after the opening
    742     // element, and the names must match. BUT the tricky bit is that the closing
    743     // element will be read by the child.
    744     //
    745     // 'endTag' is the end tag for this node, it is returned by a call to a child.
    746     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
    747 
    748     while( p && *p ) {
    749         XMLNode* node = 0;
    750 
    751         p = document->Identify( p, &node );
    752         if ( p == 0 || node == 0 ) {
    753             break;
    754         }
    755 
    756         StrPair endTag;
    757         p = node->ParseDeep( p, &endTag );
    758         if ( !p ) {
    759             DELETE_NODE( node );
    760             node = 0;
    761             if ( !document->Error() ) {
    762                 document->SetError( XML_ERROR_PARSING, 0, 0 );
    763             }
    764             break;
    765         }
    766 
    767         // We read the end tag. Return it to the parent.
    768         if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
    769             if ( parentEnd ) {
    770                 *parentEnd = static_cast<XMLElement*>(node)->value;
    771             }
    772             DELETE_NODE( node );
    773             return p;
    774         }
    775 
    776         // Handle an end tag returned to this level.
    777         // And handle a bunch of annoying errors.
    778         XMLElement* ele = node->ToElement();
    779         if ( ele ) {
    780             if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
    781                 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
    782                 p = 0;
    783             }
    784             else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
    785                 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
    786                 p = 0;
    787             }
    788             else if ( !endTag.Empty() ) {
    789                 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
    790                     document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
    791                     p = 0;
    792                 }
    793             }
    794         }
    795         if ( p == 0 ) {
    796             DELETE_NODE( node );
    797             node = 0;
    798         }
    799         if ( node ) {
    800             this->InsertEndChild( node );
    801         }
    802     }
    803     return 0;
    804 }
    805 
    806 // --------- XMLText ---------- //
    807 char* XMLText::ParseDeep( char* p, StrPair* )
    808 {
    809     const char* start = p;
    810     if ( this->CData() ) {
    811         p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
    812         if ( !p ) {
    813             document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
    814         }
    815         return p;
    816     }
    817     else {
    818         p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
    819         if ( !p ) {
    820             document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
    821         }
    822         if ( p && *p ) {
    823             return p-1;
    824         }
    825     }
    826     return 0;
    827 }
    828 
    829 
    830 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
    831 {
    832     if ( !doc ) {
    833         doc = document;
    834     }
    835     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
    836     text->SetCData( this->CData() );
    837     return text;
    838 }
    839 
    840 
    841 bool XMLText::ShallowEqual( const XMLNode* compare ) const
    842 {
    843     return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
    844 }
    845 
    846 
    847 bool XMLText::Accept( XMLVisitor* visitor ) const
    848 {
    849     return visitor->Visit( *this );
    850 }
    851 
    852 
    853 // --------- XMLComment ---------- //
    854 
    855 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
    856 {
    857 }
    858 
    859 
    860 XMLComment::~XMLComment()
    861 {
    862     //printf( "~XMLComment\n" );
    863 }
    864 
    865 
    866 char* XMLComment::ParseDeep( char* p, StrPair* )
    867 {
    868     // Comment parses as text.
    869     const char* start = p;
    870     p = value.ParseText( p, "-->", StrPair::COMMENT );
    871     if ( p == 0 ) {
    872         document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
    873     }
    874     return p;
    875 }
    876 
    877 
    878 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
    879 {
    880     if ( !doc ) {
    881         doc = document;
    882     }
    883     XMLComment* comment = doc->NewComment( Value() );    // fixme: this will always allocate memory. Intern?
    884     return comment;
    885 }
    886 
    887 
    888 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
    889 {
    890     return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
    891 }
    892 
    893 
    894 bool XMLComment::Accept( XMLVisitor* visitor ) const
    895 {
    896     return visitor->Visit( *this );
    897 }
    898 
    899 
    900 // --------- XMLDeclaration ---------- //
    901 
    902 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
    903 {
    904 }
    905 
    906 
    907 XMLDeclaration::~XMLDeclaration()
    908 {
    909     //printf( "~XMLDeclaration\n" );
    910 }
    911 
    912 
    913 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
    914 {
    915     // Declaration parses as text.
    916     const char* start = p;
    917     p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
    918     if ( p == 0 ) {
    919         document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
    920     }
    921     return p;
    922 }
    923 
    924 
    925 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
    926 {
    927     if ( !doc ) {
    928         doc = document;
    929     }
    930     XMLDeclaration* dec = doc->NewDeclaration( Value() );    // fixme: this will always allocate memory. Intern?
    931     return dec;
    932 }
    933 
    934 
    935 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
    936 {
    937     return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
    938 }
    939 
    940 
    941 
    942 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
    943 {
    944     return visitor->Visit( *this );
    945 }
    946 
    947 // --------- XMLUnknown ---------- //
    948 
    949 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
    950 {
    951 }
    952 
    953 
    954 XMLUnknown::~XMLUnknown()
    955 {
    956 }
    957 
    958 
    959 char* XMLUnknown::ParseDeep( char* p, StrPair* )
    960 {
    961     // Unknown parses as text.
    962     const char* start = p;
    963 
    964     p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
    965     if ( !p ) {
    966         document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
    967     }
    968     return p;
    969 }
    970 
    971 
    972 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
    973 {
    974     if ( !doc ) {
    975         doc = document;
    976     }
    977     XMLUnknown* text = doc->NewUnknown( Value() );    // fixme: this will always allocate memory. Intern?
    978     return text;
    979 }
    980 
    981 
    982 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
    983 {
    984     return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
    985 }
    986 
    987 
    988 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
    989 {
    990     return visitor->Visit( *this );
    991 }
    992 
    993 // --------- XMLAttribute ---------- //
    994 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
    995 {
    996     // Parse using the name rules: bug fix, was using ParseText before
    997     p = name.ParseName( p );
    998     if ( !p || !*p ) return 0;
    999 
   1000     // Skip white space before =
   1001     p = XMLUtil::SkipWhiteSpace( p );
   1002     if ( !p || *p != '=' ) return 0;
   1003 
   1004     ++p;    // move up to opening quote
   1005     p = XMLUtil::SkipWhiteSpace( p );
   1006     if ( *p != '\"' && *p != '\'' ) return 0;
   1007 
   1008     char endTag[2] = { *p, 0 };
   1009     ++p;    // move past opening quote
   1010 
   1011     p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
   1012     return p;
   1013 }
   1014 
   1015 
   1016 void XMLAttribute::SetName( const char* n )
   1017 {
   1018     name.SetStr( n );
   1019 }
   1020 
   1021 
   1022 int XMLAttribute::QueryIntValue( int* value ) const
   1023 {
   1024     if ( XMLUtil::ToInt( Value(), value ))
   1025         return XML_NO_ERROR;
   1026     return XML_WRONG_ATTRIBUTE_TYPE;
   1027 }
   1028 
   1029 
   1030 int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
   1031 {
   1032     if ( XMLUtil::ToUnsigned( Value(), value ))
   1033         return XML_NO_ERROR;
   1034     return XML_WRONG_ATTRIBUTE_TYPE;
   1035 }
   1036 
   1037 
   1038 int XMLAttribute::QueryBoolValue( bool* value ) const
   1039 {
   1040     if ( XMLUtil::ToBool( Value(), value )) {
   1041         return XML_NO_ERROR;
   1042     }
   1043     return XML_WRONG_ATTRIBUTE_TYPE;
   1044 }
   1045 
   1046 
   1047 int XMLAttribute::QueryFloatValue( float* value ) const
   1048 {
   1049     if ( XMLUtil::ToFloat( Value(), value ))
   1050         return XML_NO_ERROR;
   1051     return XML_WRONG_ATTRIBUTE_TYPE;
   1052 }
   1053 
   1054 
   1055 int XMLAttribute::QueryDoubleValue( double* value ) const
   1056 {
   1057     if ( XMLUtil::ToDouble( Value(), value ))
   1058         return XML_NO_ERROR;
   1059     return XML_WRONG_ATTRIBUTE_TYPE;
   1060 }
   1061 
   1062 
   1063 void XMLAttribute::SetAttribute( const char* v )
   1064 {
   1065     value.SetStr( v );
   1066 }
   1067 
   1068 
   1069 void XMLAttribute::SetAttribute( int v )
   1070 {
   1071     char buf[BUF_SIZE];
   1072     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1073     value.SetStr( buf );
   1074 }
   1075 
   1076 
   1077 void XMLAttribute::SetAttribute( unsigned v )
   1078 {
   1079     char buf[BUF_SIZE];
   1080     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1081     value.SetStr( buf );
   1082 }
   1083 
   1084 
   1085 void XMLAttribute::SetAttribute( bool v )
   1086 {
   1087     char buf[BUF_SIZE];
   1088     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1089     value.SetStr( buf );
   1090 }
   1091 
   1092 void XMLAttribute::SetAttribute( double v )
   1093 {
   1094     char buf[BUF_SIZE];
   1095     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1096     value.SetStr( buf );
   1097 }
   1098 
   1099 void XMLAttribute::SetAttribute( float v )
   1100 {
   1101     char buf[BUF_SIZE];
   1102     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1103     value.SetStr( buf );
   1104 }
   1105 
   1106 
   1107 // --------- XMLElement ---------- //
   1108 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
   1109     closingType( 0 ),
   1110     rootAttribute( 0 )
   1111 {
   1112 }
   1113 
   1114 
   1115 XMLElement::~XMLElement()
   1116 {
   1117     while( rootAttribute ) {
   1118         XMLAttribute* next = rootAttribute->next;
   1119         DELETE_ATTRIBUTE( rootAttribute );
   1120         rootAttribute = next;
   1121     }
   1122 }
   1123 
   1124 
   1125 XMLAttribute* XMLElement::FindAttribute( const char* name )
   1126 {
   1127     XMLAttribute* a = 0;
   1128     for( a=rootAttribute; a; a = a->next ) {
   1129         if ( XMLUtil::StringEqual( a->Name(), name ) )
   1130             return a;
   1131     }
   1132     return 0;
   1133 }
   1134 
   1135 
   1136 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
   1137 {
   1138     XMLAttribute* a = 0;
   1139     for( a=rootAttribute; a; a = a->next ) {
   1140         if ( XMLUtil::StringEqual( a->Name(), name ) )
   1141             return a;
   1142     }
   1143     return 0;
   1144 }
   1145 
   1146 
   1147 const char* XMLElement::Attribute( const char* name, const char* value ) const
   1148 {
   1149     const XMLAttribute* a = FindAttribute( name );
   1150     if ( !a )
   1151         return 0;
   1152     if ( !value || XMLUtil::StringEqual( a->Value(), value ))
   1153         return a->Value();
   1154     return 0;
   1155 }
   1156 
   1157 
   1158 const char* XMLElement::GetText() const
   1159 {
   1160     if ( FirstChild() && FirstChild()->ToText() ) {
   1161         return FirstChild()->ToText()->Value();
   1162     }
   1163     return 0;
   1164 }
   1165 
   1166 
   1167 int XMLElement::QueryIntText( int* _value ) const
   1168 {
   1169     if ( FirstChild() && FirstChild()->ToText() ) {
   1170         const char* t = FirstChild()->ToText()->Value();
   1171         if ( XMLUtil::ToInt( t, _value ) ) {
   1172             return XML_SUCCESS;
   1173         }
   1174         return XML_CAN_NOT_CONVERT_TEXT;
   1175     }
   1176     return XML_NO_TEXT_NODE;
   1177 }
   1178 
   1179 
   1180 int XMLElement::QueryUnsignedText( unsigned* _value ) const
   1181 {
   1182     if ( FirstChild() && FirstChild()->ToText() ) {
   1183         const char* t = FirstChild()->ToText()->Value();
   1184         if ( XMLUtil::ToUnsigned( t, _value ) ) {
   1185             return XML_SUCCESS;
   1186         }
   1187         return XML_CAN_NOT_CONVERT_TEXT;
   1188     }
   1189     return XML_NO_TEXT_NODE;
   1190 }
   1191 
   1192 
   1193 int XMLElement::QueryBoolText( bool* _value ) const
   1194 {
   1195     if ( FirstChild() && FirstChild()->ToText() ) {
   1196         const char* t = FirstChild()->ToText()->Value();
   1197         if ( XMLUtil::ToBool( t, _value ) ) {
   1198             return XML_SUCCESS;
   1199         }
   1200         return XML_CAN_NOT_CONVERT_TEXT;
   1201     }
   1202     return XML_NO_TEXT_NODE;
   1203 }
   1204 
   1205 
   1206 int XMLElement::QueryDoubleText( double* _value ) const
   1207 {
   1208     if ( FirstChild() && FirstChild()->ToText() ) {
   1209         const char* t = FirstChild()->ToText()->Value();
   1210         if ( XMLUtil::ToDouble( t, _value ) ) {
   1211             return XML_SUCCESS;
   1212         }
   1213         return XML_CAN_NOT_CONVERT_TEXT;
   1214     }
   1215     return XML_NO_TEXT_NODE;
   1216 }
   1217 
   1218 
   1219 int XMLElement::QueryFloatText( float* _value ) const
   1220 {
   1221     if ( FirstChild() && FirstChild()->ToText() ) {
   1222         const char* t = FirstChild()->ToText()->Value();
   1223         if ( XMLUtil::ToFloat( t, _value ) ) {
   1224             return XML_SUCCESS;
   1225         }
   1226         return XML_CAN_NOT_CONVERT_TEXT;
   1227     }
   1228     return XML_NO_TEXT_NODE;
   1229 }
   1230 
   1231 
   1232 
   1233 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
   1234 {
   1235     XMLAttribute* last = 0;
   1236     XMLAttribute* attrib = 0;
   1237     for( attrib = rootAttribute;
   1238          attrib;
   1239          last = attrib, attrib = attrib->next )
   1240     {
   1241         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
   1242             break;
   1243         }
   1244     }
   1245     if ( !attrib ) {
   1246         attrib = new (document->attributePool.Alloc() ) XMLAttribute();
   1247         attrib->memPool = &document->attributePool;
   1248         if ( last ) {
   1249             last->next = attrib;
   1250         }
   1251         else {
   1252             rootAttribute = attrib;
   1253         }
   1254         attrib->SetName( name );
   1255     }
   1256     return attrib;
   1257 }
   1258 
   1259 
   1260 void XMLElement::DeleteAttribute( const char* name )
   1261 {
   1262     XMLAttribute* prev = 0;
   1263     for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
   1264         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
   1265             if ( prev ) {
   1266                 prev->next = a->next;
   1267             }
   1268             else {
   1269                 rootAttribute = a->next;
   1270             }
   1271             DELETE_ATTRIBUTE( a );
   1272             break;
   1273         }
   1274         prev = a;
   1275     }
   1276 }
   1277 
   1278 
   1279 char* XMLElement::ParseAttributes( char* p )
   1280 {
   1281     const char* start = p;
   1282     XMLAttribute* prevAttribute = 0;
   1283 
   1284     // Read the attributes.
   1285     while( p ) {
   1286         p = XMLUtil::SkipWhiteSpace( p );
   1287         if ( !p || !(*p) ) {
   1288             document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
   1289             return 0;
   1290         }
   1291 
   1292         // attribute.
   1293         if ( XMLUtil::IsAlpha( *p ) ) {
   1294             XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
   1295             attrib->memPool = &document->attributePool;
   1296 
   1297             p = attrib->ParseDeep( p, document->ProcessEntities() );
   1298             if ( !p || Attribute( attrib->Name() ) ) {
   1299                 DELETE_ATTRIBUTE( attrib );
   1300                 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
   1301                 return 0;
   1302             }
   1303             // There is a minor bug here: if the attribute in the source xml
   1304             // document is duplicated, it will not be detected and the
   1305             // attribute will be doubly added. However, tracking the 'prevAttribute'
   1306             // avoids re-scanning the attribute list. Preferring performance for
   1307             // now, may reconsider in the future.
   1308             if ( prevAttribute ) {
   1309                 prevAttribute->next = attrib;
   1310             }
   1311             else {
   1312                 rootAttribute = attrib;
   1313             }
   1314             prevAttribute = attrib;
   1315         }
   1316         // end of the tag
   1317         else if ( *p == '/' && *(p+1) == '>' ) {
   1318             closingType = CLOSED;
   1319             return p+2;    // done; sealed element.
   1320         }
   1321         // end of the tag
   1322         else if ( *p == '>' ) {
   1323             ++p;
   1324             break;
   1325         }
   1326         else {
   1327             document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
   1328             return 0;
   1329         }
   1330     }
   1331     return p;
   1332 }
   1333 
   1334 
   1335 //
   1336 //    <ele></ele>
   1337 //    <ele>foo<b>bar</b></ele>
   1338 //
   1339 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
   1340 {
   1341     // Read the element name.
   1342     p = XMLUtil::SkipWhiteSpace( p );
   1343     if ( !p ) return 0;
   1344 
   1345     // The closing element is the </element> form. It is
   1346     // parsed just like a regular element then deleted from
   1347     // the DOM.
   1348     if ( *p == '/' ) {
   1349         closingType = CLOSING;
   1350         ++p;
   1351     }
   1352 
   1353     p = value.ParseName( p );
   1354     if ( value.Empty() ) return 0;
   1355 
   1356     p = ParseAttributes( p );
   1357     if ( !p || !*p || closingType )
   1358         return p;
   1359 
   1360     p = XMLNode::ParseDeep( p, strPair );
   1361     return p;
   1362 }
   1363 
   1364 
   1365 
   1366 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
   1367 {
   1368     if ( !doc ) {
   1369         doc = document;
   1370     }
   1371     XMLElement* element = doc->NewElement( Value() );                    // fixme: this will always allocate memory. Intern?
   1372     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
   1373         element->SetAttribute( a->Name(), a->Value() );                    // fixme: this will always allocate memory. Intern?
   1374     }
   1375     return element;
   1376 }
   1377 
   1378 
   1379 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
   1380 {
   1381     const XMLElement* other = compare->ToElement();
   1382     if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
   1383 
   1384         const XMLAttribute* a=FirstAttribute();
   1385         const XMLAttribute* b=other->FirstAttribute();
   1386 
   1387         while ( a && b ) {
   1388             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
   1389                 return false;
   1390             }
   1391             a = a->Next();
   1392             b = b->Next();
   1393         }
   1394         if ( a || b ) {
   1395             // different count
   1396             return false;
   1397         }
   1398         return true;
   1399     }
   1400     return false;
   1401 }
   1402 
   1403 
   1404 bool XMLElement::Accept( XMLVisitor* visitor ) const
   1405 {
   1406     if ( visitor->VisitEnter( *this, rootAttribute ) )
   1407     {
   1408         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
   1409         {
   1410             if ( !node->Accept( visitor ) )
   1411                 break;
   1412         }
   1413     }
   1414     return visitor->VisitExit( *this );
   1415 }
   1416 
   1417 
   1418 // --------- XMLDocument ----------- //
   1419 XMLDocument::XMLDocument( bool _processEntities ) :
   1420     XMLNode( 0 ),
   1421     writeBOM( false ),
   1422     processEntities( _processEntities ),
   1423     errorID( 0 ),
   1424     errorStr1( 0 ),
   1425     errorStr2( 0 ),
   1426     charBuffer( 0 )
   1427 {
   1428     document = this;    // avoid warning about 'this' in initializer list
   1429 }
   1430 
   1431 
   1432 XMLDocument::~XMLDocument()
   1433 {
   1434     DeleteChildren();
   1435     delete [] charBuffer;
   1436 
   1437 #if 0
   1438     textPool.Trace( "text" );
   1439     elementPool.Trace( "element" );
   1440     commentPool.Trace( "comment" );
   1441     attributePool.Trace( "attribute" );
   1442 #endif
   1443 
   1444     TIXMLASSERT( textPool.CurrentAllocs() == 0 );
   1445     TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
   1446     TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
   1447     TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
   1448 }
   1449 
   1450 
   1451 void XMLDocument::InitDocument()
   1452 {
   1453     errorID = XML_NO_ERROR;
   1454     errorStr1 = 0;
   1455     errorStr2 = 0;
   1456 
   1457     delete [] charBuffer;
   1458     charBuffer = 0;
   1459 
   1460 }
   1461 
   1462 
   1463 XMLElement* XMLDocument::NewElement( const char* name )
   1464 {
   1465     XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
   1466     ele->memPool = &elementPool;
   1467     ele->SetName( name );
   1468     return ele;
   1469 }
   1470 
   1471 
   1472 XMLComment* XMLDocument::NewComment( const char* str )
   1473 {
   1474     XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
   1475     comment->memPool = &commentPool;
   1476     comment->SetValue( str );
   1477     return comment;
   1478 }
   1479 
   1480 
   1481 XMLText* XMLDocument::NewText( const char* str )
   1482 {
   1483     XMLText* text = new (textPool.Alloc()) XMLText( this );
   1484     text->memPool = &textPool;
   1485     text->SetValue( str );
   1486     return text;
   1487 }
   1488 
   1489 
   1490 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
   1491 {
   1492     XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
   1493     dec->memPool = &commentPool;
   1494     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
   1495     return dec;
   1496 }
   1497 
   1498 
   1499 XMLUnknown* XMLDocument::NewUnknown( const char* str )
   1500 {
   1501     XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
   1502     unk->memPool = &commentPool;
   1503     unk->SetValue( str );
   1504     return unk;
   1505 }
   1506 
   1507 
   1508 int XMLDocument::LoadFile( const char* filename )
   1509 {
   1510     DeleteChildren();
   1511     InitDocument();
   1512 
   1513 #if defined(_MSC_VER)
   1514 #pragma warning ( push )
   1515 #pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.
   1516 #endif
   1517     FILE* fp = fopen( filename, "rb" );
   1518 #if defined(_MSC_VER)
   1519 #pragma warning ( pop )
   1520 #endif
   1521     if ( !fp ) {
   1522         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
   1523         return errorID;
   1524     }
   1525     LoadFile( fp );
   1526     fclose( fp );
   1527     return errorID;
   1528 }
   1529 
   1530 
   1531 int XMLDocument::LoadFile( FILE* fp )
   1532 {
   1533     DeleteChildren();
   1534     InitDocument();
   1535 
   1536     fseek( fp, 0, SEEK_END );
   1537     unsigned size = ftell( fp );
   1538     fseek( fp, 0, SEEK_SET );
   1539 
   1540     if ( size == 0 ) {
   1541         return errorID;
   1542     }
   1543 
   1544     charBuffer = new char[size+1];
   1545     size_t read = fread( charBuffer, 1, size, fp );
   1546     if ( read != size ) {
   1547         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
   1548         return errorID;
   1549     }
   1550 
   1551     charBuffer[size] = 0;
   1552 
   1553     const char* p = charBuffer;
   1554     p = XMLUtil::SkipWhiteSpace( p );
   1555     p = XMLUtil::ReadBOM( p, &writeBOM );
   1556     if ( !p || !*p ) {
   1557         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   1558         return errorID;
   1559     }
   1560 
   1561     ParseDeep( charBuffer + (p-charBuffer), 0 );
   1562     return errorID;
   1563 }
   1564 
   1565 
   1566 int XMLDocument::SaveFile( const char* filename )
   1567 {
   1568 #if defined(_MSC_VER)
   1569 #pragma warning ( push )
   1570 #pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.
   1571 #endif
   1572     int fd = open(filename, O_RDWR|O_CREAT, 0644);
   1573     FILE* fp = fdopen(fd, "w");
   1574     //FILE* fp = fopen( filename, "w" );
   1575 #if defined(_MSC_VER)
   1576 #pragma warning ( pop )
   1577 #endif
   1578     if ( !fp ) {
   1579         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
   1580         return errorID;
   1581     }
   1582     SaveFile(fp);
   1583     fclose( fp );
   1584     return errorID;
   1585 }
   1586 
   1587 
   1588 int XMLDocument::SaveFile( FILE* fp )
   1589 {
   1590     XMLPrinter stream( fp );
   1591     Print( &stream );
   1592     return errorID;
   1593 }
   1594 
   1595 
   1596 int XMLDocument::Parse( const char* p )
   1597 {
   1598     DeleteChildren();
   1599     InitDocument();
   1600 
   1601     if ( !p || !*p ) {
   1602         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   1603         return errorID;
   1604     }
   1605     p = XMLUtil::SkipWhiteSpace( p );
   1606     p = XMLUtil::ReadBOM( p, &writeBOM );
   1607     if ( !p || !*p ) {
   1608         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   1609         return errorID;
   1610     }
   1611 
   1612     size_t len = strlen( p );
   1613     charBuffer = new char[ len+1 ];
   1614     memcpy( charBuffer, p, len+1 );
   1615 
   1616 
   1617     ParseDeep( charBuffer, 0 );
   1618     return errorID;
   1619 }
   1620 
   1621 
   1622 void XMLDocument::Print( XMLPrinter* streamer )
   1623 {
   1624     XMLPrinter stdStreamer( stdout );
   1625     if ( !streamer )
   1626         streamer = &stdStreamer;
   1627     Accept( streamer );
   1628 }
   1629 
   1630 
   1631 void XMLDocument::SetError( int error, const char* str1, const char* str2 )
   1632 {
   1633     errorID = error;
   1634     errorStr1 = str1;
   1635     errorStr2 = str2;
   1636 }
   1637 
   1638 
   1639 void XMLDocument::PrintError() const
   1640 {
   1641     if ( errorID ) {
   1642         static const int LEN = 20;
   1643         char buf1[LEN] = { 0 };
   1644         char buf2[LEN] = { 0 };
   1645 
   1646         if ( errorStr1 ) {
   1647             TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
   1648         }
   1649         if ( errorStr2 ) {
   1650             TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
   1651         }
   1652 
   1653         printf( "XMLDocument error id=%d str1=%s str2=%s\n",
   1654                 errorID, buf1, buf2 );
   1655     }
   1656 }
   1657 
   1658 
   1659 XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
   1660     elementJustOpened( false ),
   1661     firstElement( true ),
   1662     fp( file ),
   1663     depth( 0 ),
   1664     textDepth( -1 ),
   1665     processEntities( true ),
   1666     compactMode( compact )
   1667 {
   1668     for( int i=0; i<ENTITY_RANGE; ++i ) {
   1669         entityFlag[i] = false;
   1670         restrictedEntityFlag[i] = false;
   1671     }
   1672     for( int i=0; i<NUM_ENTITIES; ++i ) {
   1673         TIXMLASSERT( entities[i].value < ENTITY_RANGE );
   1674         if ( entities[i].value < ENTITY_RANGE ) {
   1675             entityFlag[ (int)entities[i].value ] = true;
   1676         }
   1677     }
   1678     restrictedEntityFlag[(int)'&'] = true;
   1679     restrictedEntityFlag[(int)'<'] = true;
   1680     restrictedEntityFlag[(int)'>'] = true;    // not required, but consistency is nice
   1681     buffer.Push( 0 );
   1682 }
   1683 
   1684 
   1685 void XMLPrinter::Print( const char* format, ... )
   1686 {
   1687     va_list     va;
   1688     va_start( va, format );
   1689 
   1690     if ( fp ) {
   1691         vfprintf( fp, format, va );
   1692     }
   1693     else {
   1694         // This seems brutally complex. Haven't figured out a better
   1695         // way on windows.
   1696         #ifdef _MSC_VER
   1697             int len = -1;
   1698             int expand = 1000;
   1699             while ( len < 0 ) {
   1700                 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
   1701                 if ( len < 0 ) {
   1702                     expand *= 3/2;
   1703                     accumulator.PushArr( expand );
   1704                 }
   1705             }
   1706             char* p = buffer.PushArr( len ) - 1;
   1707             memcpy( p, accumulator.Mem(), len+1 );
   1708         #else
   1709             int len = vsnprintf( 0, 0, format, va );
   1710             // Close out and re-start the va-args
   1711             va_end( va );
   1712             va_start( va, format );
   1713             char* p = buffer.PushArr( len ) - 1;
   1714             vsnprintf( p, len+1, format, va );
   1715         #endif
   1716     }
   1717     va_end( va );
   1718 }
   1719 
   1720 
   1721 void XMLPrinter::PrintSpace( int depth )
   1722 {
   1723     for( int i=0; i<depth; ++i ) {
   1724         Print( "    " );
   1725     }
   1726 }
   1727 
   1728 
   1729 void XMLPrinter::PrintString( const char* p, bool restricted )
   1730 {
   1731     // Look for runs of bytes between entities to print.
   1732     const char* q = p;
   1733     const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
   1734 
   1735     if ( processEntities ) {
   1736         while ( *q ) {
   1737             // Remember, char is sometimes signed. (How many times has that bitten me?)
   1738             if ( *q > 0 && *q < ENTITY_RANGE ) {
   1739                 // Check for entities. If one is found, flush
   1740                 // the stream up until the entity, write the
   1741                 // entity, and keep looking.
   1742                 if ( flag[(unsigned)(*q)] ) {
   1743                     while ( p < q ) {
   1744                         Print( "%c", *p );
   1745                         ++p;
   1746                     }
   1747                     for( int i=0; i<NUM_ENTITIES; ++i ) {
   1748                         if ( entities[i].value == *q ) {
   1749                             Print( "&%s;", entities[i].pattern );
   1750                             break;
   1751                         }
   1752                     }
   1753                     ++p;
   1754                 }
   1755             }
   1756             ++q;
   1757         }
   1758     }
   1759     // Flush the remaining string. This will be the entire
   1760     // string if an entity wasn't found.
   1761     if ( !processEntities || (q-p > 0) ) {
   1762         Print( "%s", p );
   1763     }
   1764 }
   1765 
   1766 
   1767 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
   1768 {
   1769     static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
   1770     if ( writeBOM ) {
   1771         Print( "%s", bom );
   1772     }
   1773     if ( writeDec ) {
   1774         PushDeclaration( "xml version=\"1.0\"" );
   1775     }
   1776 }
   1777 
   1778 
   1779 void XMLPrinter::OpenElement( const char* name )
   1780 {
   1781     if ( elementJustOpened ) {
   1782         SealElement();
   1783     }
   1784     stack.Push( name );
   1785 
   1786     if ( textDepth < 0 && !firstElement && !compactMode ) {
   1787         Print( "\n" );
   1788         PrintSpace( depth );
   1789     }
   1790 
   1791     Print( "<%s", name );
   1792     elementJustOpened = true;
   1793     firstElement = false;
   1794     ++depth;
   1795 }
   1796 
   1797 
   1798 void XMLPrinter::PushAttribute( const char* name, const char* value )
   1799 {
   1800     TIXMLASSERT( elementJustOpened );
   1801     Print( " %s=\"", name );
   1802     PrintString( value, false );
   1803     Print( "\"" );
   1804 }
   1805 
   1806 
   1807 void XMLPrinter::PushAttribute( const char* name, int v )
   1808 {
   1809     char buf[BUF_SIZE];
   1810     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1811     PushAttribute( name, buf );
   1812 }
   1813 
   1814 
   1815 void XMLPrinter::PushAttribute( const char* name, unsigned v )
   1816 {
   1817     char buf[BUF_SIZE];
   1818     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1819     PushAttribute( name, buf );
   1820 }
   1821 
   1822 
   1823 void XMLPrinter::PushAttribute( const char* name, bool v )
   1824 {
   1825     char buf[BUF_SIZE];
   1826     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1827     PushAttribute( name, buf );
   1828 }
   1829 
   1830 
   1831 void XMLPrinter::PushAttribute( const char* name, double v )
   1832 {
   1833     char buf[BUF_SIZE];
   1834     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1835     PushAttribute( name, buf );
   1836 }
   1837 
   1838 
   1839 void XMLPrinter::CloseElement()
   1840 {
   1841     --depth;
   1842     const char* name = stack.Pop();
   1843 
   1844     if ( elementJustOpened ) {
   1845         Print( "/>" );
   1846     }
   1847     else {
   1848         if ( textDepth < 0 && !compactMode) {
   1849             Print( "\n" );
   1850             PrintSpace( depth );
   1851         }
   1852         Print( "</%s>", name );
   1853     }
   1854 
   1855     if ( textDepth == depth )
   1856         textDepth = -1;
   1857     if ( depth == 0 && !compactMode)
   1858         Print( "\n" );
   1859     elementJustOpened = false;
   1860 }
   1861 
   1862 
   1863 void XMLPrinter::SealElement()
   1864 {
   1865     elementJustOpened = false;
   1866     Print( ">" );
   1867 }
   1868 
   1869 
   1870 void XMLPrinter::PushText( const char* text, bool cdata )
   1871 {
   1872     textDepth = depth-1;
   1873 
   1874     if ( elementJustOpened ) {
   1875         SealElement();
   1876     }
   1877     if ( cdata ) {
   1878         Print( "<![CDATA[" );
   1879         Print( "%s", text );
   1880         Print( "]]>" );
   1881     }
   1882     else {
   1883         PrintString( text, true );
   1884     }
   1885 }
   1886 
   1887 void XMLPrinter::PushText( int value )
   1888 {
   1889     char buf[BUF_SIZE];
   1890     XMLUtil::ToStr( value, buf, BUF_SIZE );
   1891     PushText( buf, false );
   1892 }
   1893 
   1894 
   1895 void XMLPrinter::PushText( unsigned value )
   1896 {
   1897     char buf[BUF_SIZE];
   1898     XMLUtil::ToStr( value, buf, BUF_SIZE );
   1899     PushText( buf, false );
   1900 }
   1901 
   1902 
   1903 void XMLPrinter::PushText( bool value )
   1904 {
   1905     char buf[BUF_SIZE];
   1906     XMLUtil::ToStr( value, buf, BUF_SIZE );
   1907     PushText( buf, false );
   1908 }
   1909 
   1910 
   1911 void XMLPrinter::PushText( float value )
   1912 {
   1913     char buf[BUF_SIZE];
   1914     XMLUtil::ToStr( value, buf, BUF_SIZE );
   1915     PushText( buf, false );
   1916 }
   1917 
   1918 
   1919 void XMLPrinter::PushText( double value )
   1920 {
   1921     char buf[BUF_SIZE];
   1922     XMLUtil::ToStr( value, buf, BUF_SIZE );
   1923     PushText( buf, false );
   1924 }
   1925 
   1926 
   1927 void XMLPrinter::PushComment( const char* comment )
   1928 {
   1929     if ( elementJustOpened ) {
   1930         SealElement();
   1931     }
   1932     if ( textDepth < 0 && !firstElement && !compactMode) {
   1933         Print( "\n" );
   1934         PrintSpace( depth );
   1935     }
   1936     firstElement = false;
   1937     Print( "<!--%s-->", comment );
   1938 }
   1939 
   1940 
   1941 void XMLPrinter::PushDeclaration( const char* value )
   1942 {
   1943     if ( elementJustOpened ) {
   1944         SealElement();
   1945     }
   1946     if ( textDepth < 0 && !firstElement && !compactMode) {
   1947         Print( "\n" );
   1948         PrintSpace( depth );
   1949     }
   1950     firstElement = false;
   1951     Print( "<?%s?>", value );
   1952 }
   1953 
   1954 
   1955 void XMLPrinter::PushUnknown( const char* value )
   1956 {
   1957     if ( elementJustOpened ) {
   1958         SealElement();
   1959     }
   1960     if ( textDepth < 0 && !firstElement && !compactMode) {
   1961         Print( "\n" );
   1962         PrintSpace( depth );
   1963     }
   1964     firstElement = false;
   1965     Print( "<!%s>", value );
   1966 }
   1967 
   1968 
   1969 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
   1970 {
   1971     processEntities = doc.ProcessEntities();
   1972     if ( doc.HasBOM() ) {
   1973         PushHeader( true, false );
   1974     }
   1975     return true;
   1976 }
   1977 
   1978 
   1979 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
   1980 {
   1981     OpenElement( element.Name() );
   1982     while ( attribute ) {
   1983         PushAttribute( attribute->Name(), attribute->Value() );
   1984         attribute = attribute->Next();
   1985     }
   1986     return true;
   1987 }
   1988 
   1989 
   1990 bool XMLPrinter::VisitExit( const XMLElement& )
   1991 {
   1992     CloseElement();
   1993     return true;
   1994 }
   1995 
   1996 
   1997 bool XMLPrinter::Visit( const XMLText& text )
   1998 {
   1999     PushText( text.Value(), text.CData() );
   2000     return true;
   2001 }
   2002 
   2003 
   2004 bool XMLPrinter::Visit( const XMLComment& comment )
   2005 {
   2006     PushComment( comment.Value() );
   2007     return true;
   2008 }
   2009 
   2010 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
   2011 {
   2012     PushDeclaration( declaration.Value() );
   2013     return true;
   2014 }
   2015 
   2016 
   2017 bool XMLPrinter::Visit( const XMLUnknown& unknown )
   2018 {
   2019     PushUnknown( unknown.Value() );
   2020     return true;
   2021 }
   2022