Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:19:52

0001 /*

0002 Original code by Lee Thomason (www.grinninglizard.com)

0003 

0004 This software is provided 'as-is', without any express or implied

0005 warranty. In no event will the authors be held liable for any

0006 damages arising from the use of this software.

0007 

0008 Permission is granted to anyone to use this software for any

0009 purpose, including commercial applications, and to alter it and

0010 redistribute it freely, subject to the following restrictions:

0011 

0012 1. The origin of this software must not be misrepresented; you must

0013 not claim that you wrote the original software. If you use this

0014 software in a product, an acknowledgment in the product documentation

0015 would be appreciated but is not required.

0016 

0017 2. Altered source versions must be plainly marked as such, and

0018 must not be misrepresented as being the original software.

0019 

0020 3. This notice may not be removed or altered from any source

0021 distribution.

0022 */
0023 
0024 #include "tinyxml2.h"
0025 
0026 #include <new>      // yes, this one new style header, is in the Android SDK.
0027 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
0028 #   include <stddef.h>
0029 #   include <stdarg.h>
0030 #else
0031 #   include <cstddef>
0032 #   include <cstdarg>
0033 #endif
0034 
0035 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
0036     // Microsoft Visual Studio, version 2005 and higher. Not WinCE.

0037     /*int _snprintf_s(

0038        char *buffer,

0039        size_t sizeOfBuffer,

0040        size_t count,

0041        const char *format [,

0042           argument] ...

0043     );*/
0044     static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
0045     {
0046         va_list va;
0047         va_start( va, format );
0048         int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0049         va_end( va );
0050         return result;
0051     }
0052 
0053     static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
0054     {
0055         int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0056         return result;
0057     }
0058 
0059     #define TIXML_VSCPRINTF _vscprintf
0060     #define TIXML_SSCANF    sscanf_s
0061 #elif defined _MSC_VER
0062     // Microsoft Visual Studio 2003 and earlier or WinCE

0063     #define TIXML_SNPRINTF  _snprintf
0064     #define TIXML_VSNPRINTF _vsnprintf
0065     #define TIXML_SSCANF    sscanf
0066     #if (_MSC_VER < 1400 ) && (!defined WINCE)
0067         // Microsoft Visual Studio 2003 and not WinCE.

0068         #define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.

0069     #else
0070         // Microsoft Visual Studio 2003 and earlier or WinCE.

0071         static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0072         {
0073             int len = 512;
0074             for (;;) {
0075                 len = len*2;
0076                 char* str = new char[len]();
0077                 const int required = _vsnprintf(str, len, format, va);
0078                 delete[] str;
0079                 if ( required != -1 ) {
0080                     TIXMLASSERT( required >= 0 );
0081                     len = required;
0082                     break;
0083                 }
0084             }
0085             TIXMLASSERT( len >= 0 );
0086             return len;
0087         }
0088     #endif
0089 #else
0090     // GCC version 3 and higher

0091     //#warning( "Using sn* functions." )

0092     #define TIXML_SNPRINTF  snprintf
0093     #define TIXML_VSNPRINTF vsnprintf
0094     static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0095     {
0096         int len = vsnprintf( 0, 0, format, va );
0097         TIXMLASSERT( len >= 0 );
0098         return len;
0099     }
0100     #define TIXML_SSCANF   sscanf
0101 #endif
0102 
0103 
0104 static const char LINE_FEED             = (char)0x0a;           // all line endings are normalized to LF

0105 static const char LF = LINE_FEED;
0106 static const char CARRIAGE_RETURN       = (char)0x0d;           // CR gets filtered out

0107 static const char CR = CARRIAGE_RETURN;
0108 static const char SINGLE_QUOTE          = '\'';
0109 static const char DOUBLE_QUOTE          = '\"';
0110 
0111 // Bunch of unicode info at:

0112 //      http://www.unicode.org/faq/utf_bom.html

0113 //  ef bb bf (Microsoft "lead bytes") - designates UTF-8

0114 
0115 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
0116 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
0117 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
0118 
0119 namespace tinyxml2
0120 {
0121 
0122 struct Entity {
0123     const char* pattern;
0124     int length;
0125     char value;
0126 };
0127 
0128 static const int NUM_ENTITIES = 5;
0129 static const Entity entities[NUM_ENTITIES] = {
0130     { "quot", 4,    DOUBLE_QUOTE },
0131     { "amp", 3,     '&'  },
0132     { "apos", 4,    SINGLE_QUOTE },
0133     { "lt", 2,      '<'  },
0134     { "gt", 2,      '>'  }
0135 };
0136 
0137 
0138 StrPair::~StrPair()
0139 {
0140     Reset();
0141 }
0142 
0143 
0144 void StrPair::TransferTo( StrPair* other )
0145 {
0146     if ( this == other ) {
0147         return;
0148     }
0149     // This in effect implements the assignment operator by "moving"

0150     // ownership (as in auto_ptr).

0151 
0152     TIXMLASSERT( other != 0 );
0153     TIXMLASSERT( other->_flags == 0 );
0154     TIXMLASSERT( other->_start == 0 );
0155     TIXMLASSERT( other->_end == 0 );
0156 
0157     other->Reset();
0158 
0159     other->_flags = _flags;
0160     other->_start = _start;
0161     other->_end = _end;
0162 
0163     _flags = 0;
0164     _start = 0;
0165     _end = 0;
0166 }
0167 
0168 void StrPair::Reset()
0169 {
0170     if ( _flags & NEEDS_DELETE ) {
0171         delete [] _start;
0172     }
0173     _flags = 0;
0174     _start = 0;
0175     _end = 0;
0176 }
0177 
0178 
0179 void StrPair::SetStr( const char* str, int flags )
0180 {
0181     TIXMLASSERT( str );
0182     Reset();
0183     size_t len = strlen( str );
0184     TIXMLASSERT( _start == 0 );
0185     _start = new char[ len+1 ];
0186     memcpy( _start, str, len+1 );
0187     _end = _start + len;
0188     _flags = flags | NEEDS_DELETE;
0189 }
0190 
0191 
0192 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
0193 {
0194     TIXMLASSERT( p );
0195     TIXMLASSERT( endTag && *endTag );
0196 
0197     char* start = p;
0198     char  endChar = *endTag;
0199     size_t length = strlen( endTag );
0200 
0201     // Inner loop of text parsing.

0202     while ( *p ) {
0203         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
0204             Set( start, p, strFlags );
0205             return p + length;
0206         }
0207         ++p;
0208         TIXMLASSERT( p );
0209     }
0210     return 0;
0211 }
0212 
0213 
0214 char* StrPair::ParseName( char* p )
0215 {
0216     if ( !p || !(*p) ) {
0217         return 0;
0218     }
0219     if ( !XMLUtil::IsNameStartChar( *p ) ) {
0220         return 0;
0221     }
0222 
0223     char* const start = p;
0224     ++p;
0225     while ( *p && XMLUtil::IsNameChar( *p ) ) {
0226         ++p;
0227     }
0228 
0229     Set( start, p, 0 );
0230     return p;
0231 }
0232 
0233 
0234 void StrPair::CollapseWhitespace()
0235 {
0236     // Adjusting _start would cause undefined behavior on delete[]

0237     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
0238     // Trim leading space.

0239     _start = XMLUtil::SkipWhiteSpace( _start );
0240 
0241     if ( *_start ) {
0242         const char* p = _start; // the read pointer

0243         char* q = _start;   // the write pointer

0244 
0245         while( *p ) {
0246             if ( XMLUtil::IsWhiteSpace( *p )) {
0247                 p = XMLUtil::SkipWhiteSpace( p );
0248                 if ( *p == 0 ) {
0249                     break;    // don't write to q; this trims the trailing space.

0250                 }
0251                 *q = ' ';
0252                 ++q;
0253             }
0254             *q = *p;
0255             ++q;
0256             ++p;
0257         }
0258         *q = 0;
0259     }
0260 }
0261 
0262 
0263 const char* StrPair::GetStr()
0264 {
0265     TIXMLASSERT( _start );
0266     TIXMLASSERT( _end );
0267     if ( _flags & NEEDS_FLUSH ) {
0268         *_end = 0;
0269         _flags ^= NEEDS_FLUSH;
0270 
0271         if ( _flags ) {
0272             const char* p = _start; // the read pointer

0273             char* q = _start;   // the write pointer

0274 
0275             while( p < _end ) {
0276                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
0277                     // CR-LF pair becomes LF

0278                     // CR alone becomes LF

0279                     // LF-CR becomes LF

0280                     if ( *(p+1) == LF ) {
0281                         p += 2;
0282                     }
0283                     else {
0284                         ++p;
0285                     }
0286                     *q = LF;
0287                     ++q;
0288                 }
0289                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
0290                     if ( *(p+1) == CR ) {
0291                         p += 2;
0292                     }
0293                     else {
0294                         ++p;
0295                     }
0296                     *q = LF;
0297                     ++q;
0298                 }
0299                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
0300                     // Entities handled by tinyXML2:

0301                     // - special entities in the entity table [in/out]

0302                     // - numeric character reference [in]

0303                     //   &#20013; or &#x4e2d;

0304 
0305                     if ( *(p+1) == '#' ) {
0306                         const int buflen = 10;
0307                         char buf[buflen] = { 0 };
0308                         int len = 0;
0309                         char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
0310                         if ( adjusted == 0 ) {
0311                             *q = *p;
0312                             ++p;
0313                             ++q;
0314                         }
0315                         else {
0316                             TIXMLASSERT( 0 <= len && len <= buflen );
0317                             TIXMLASSERT( q + len <= adjusted );
0318                             p = adjusted;
0319                             memcpy( q, buf, len );
0320                             q += len;
0321                         }
0322                     }
0323                     else {
0324                         bool entityFound = false;
0325                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
0326                             const Entity& entity = entities[i];
0327                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
0328                                     && *( p + entity.length + 1 ) == ';' ) {
0329                                 // Found an entity - convert.

0330                                 *q = entity.value;
0331                                 ++q;
0332                                 p += entity.length + 2;
0333                                 entityFound = true;
0334                                 break;
0335                             }
0336                         }
0337                         if ( !entityFound ) {
0338                             // fixme: treat as error?

0339                             ++p;
0340                             ++q;
0341                         }
0342                     }
0343                 }
0344                 else {
0345                     *q = *p;
0346                     ++p;
0347                     ++q;
0348                 }
0349             }
0350             *q = 0;
0351         }
0352         // The loop below has plenty going on, and this

0353         // is a less useful mode. Break it out.

0354         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
0355             CollapseWhitespace();
0356         }
0357         _flags = (_flags & NEEDS_DELETE);
0358     }
0359     TIXMLASSERT( _start );
0360     return _start;
0361 }
0362 
0363 
0364 
0365 
0366 // --------- XMLUtil ----------- //

0367 
0368 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
0369 {
0370     TIXMLASSERT( p );
0371     TIXMLASSERT( bom );
0372     *bom = false;
0373     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
0374     // Check for BOM:

0375     if (    *(pu+0) == TIXML_UTF_LEAD_0
0376             && *(pu+1) == TIXML_UTF_LEAD_1
0377             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
0378         *bom = true;
0379         p += 3;
0380     }
0381     TIXMLASSERT( p );
0382     return p;
0383 }
0384 
0385 
0386 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
0387 {
0388     const unsigned long BYTE_MASK = 0xBF;
0389     const unsigned long BYTE_MARK = 0x80;
0390     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
0391 
0392     if (input < 0x80) {
0393         *length = 1;
0394     }
0395     else if ( input < 0x800 ) {
0396         *length = 2;
0397     }
0398     else if ( input < 0x10000 ) {
0399         *length = 3;
0400     }
0401     else if ( input < 0x200000 ) {
0402         *length = 4;
0403     }
0404     else {
0405         *length = 0;    // This code won't convert this correctly anyway.

0406         return;
0407     }
0408 
0409     output += *length;
0410 
0411     // Scary scary fall throughs.

0412     switch (*length) {
0413         case 4:
0414             --output;
0415             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
0416             input >>= 6;
0417         case 3:
0418             --output;
0419             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
0420             input >>= 6;
0421         case 2:
0422             --output;
0423             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
0424             input >>= 6;
0425         case 1:
0426             --output;
0427             *output = (char)(input | FIRST_BYTE_MARK[*length]);
0428             break;
0429         default:
0430             TIXMLASSERT( false );
0431     }
0432 }
0433 
0434 
0435 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
0436 {
0437     // Presume an entity, and pull it out.

0438     *length = 0;
0439 
0440     if ( *(p+1) == '#' && *(p+2) ) {
0441         unsigned long ucs = 0;
0442         TIXMLASSERT( sizeof( ucs ) >= 4 );
0443         ptrdiff_t delta = 0;
0444         unsigned mult = 1;
0445         static const char SEMICOLON = ';';
0446 
0447         if ( *(p+2) == 'x' ) {
0448             // Hexadecimal.

0449             const char* q = p+3;
0450             if ( !(*q) ) {
0451                 return 0;
0452             }
0453 
0454             q = strchr( q, SEMICOLON );
0455 
0456             if ( !q ) {
0457                 return 0;
0458             }
0459             TIXMLASSERT( *q == SEMICOLON );
0460 
0461             delta = q-p;
0462             --q;
0463 
0464             while ( *q != 'x' ) {
0465                 unsigned int digit = 0;
0466 
0467                 if ( *q >= '0' && *q <= '9' ) {
0468                     digit = *q - '0';
0469                 }
0470                 else if ( *q >= 'a' && *q <= 'f' ) {
0471                     digit = *q - 'a' + 10;
0472                 }
0473                 else if ( *q >= 'A' && *q <= 'F' ) {
0474                     digit = *q - 'A' + 10;
0475                 }
0476                 else {
0477                     return 0;
0478                 }
0479                 TIXMLASSERT( digit < 16 );
0480                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0481                 const unsigned int digitScaled = mult * digit;
0482                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0483                 ucs += digitScaled;
0484                 TIXMLASSERT( mult <= UINT_MAX / 16 );
0485                 mult *= 16;
0486                 --q;
0487             }
0488         }
0489         else {
0490             // Decimal.

0491             const char* q = p+2;
0492             if ( !(*q) ) {
0493                 return 0;
0494             }
0495 
0496             q = strchr( q, SEMICOLON );
0497 
0498             if ( !q ) {
0499                 return 0;
0500             }
0501             TIXMLASSERT( *q == SEMICOLON );
0502 
0503             delta = q-p;
0504             --q;
0505 
0506             while ( *q != '#' ) {
0507                 if ( *q >= '0' && *q <= '9' ) {
0508                     const unsigned int digit = *q - '0';
0509                     TIXMLASSERT( digit < 10 );
0510                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0511                     const unsigned int digitScaled = mult * digit;
0512                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0513                     ucs += digitScaled;
0514                 }
0515                 else {
0516                     return 0;
0517                 }
0518                 TIXMLASSERT( mult <= UINT_MAX / 10 );
0519                 mult *= 10;
0520                 --q;
0521             }
0522         }
0523         // convert the UCS to UTF-8

0524         ConvertUTF32ToUTF8( ucs, value, length );
0525         return p + delta + 1;
0526     }
0527     return p+1;
0528 }
0529 
0530 
0531 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
0532 {
0533     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
0534 }
0535 
0536 
0537 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
0538 {
0539     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
0540 }
0541 
0542 
0543 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
0544 {
0545     TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
0546 }
0547 
0548 /*

0549     ToStr() of a number is a very tricky topic.

0550     https://github.com/leethomason/tinyxml2/issues/106

0551 */
0552 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
0553 {
0554     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
0555 }
0556 
0557 
0558 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
0559 {
0560     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
0561 }
0562 
0563 
0564 void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
0565 {
0566     // horrible syntax trick to make the compiler happy about %lld

0567     TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
0568 }
0569 
0570 
0571 bool XMLUtil::ToInt( const char* str, int* value )
0572 {
0573     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
0574         return true;
0575     }
0576     return false;
0577 }
0578 
0579 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
0580 {
0581     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
0582         return true;
0583     }
0584     return false;
0585 }
0586 
0587 bool XMLUtil::ToBool( const char* str, bool* value )
0588 {
0589     int ival = 0;
0590     if ( ToInt( str, &ival )) {
0591         *value = (ival==0) ? false : true;
0592         return true;
0593     }
0594     if ( StringEqual( str, "true" ) ) {
0595         *value = true;
0596         return true;
0597     }
0598     else if ( StringEqual( str, "false" ) ) {
0599         *value = false;
0600         return true;
0601     }
0602     return false;
0603 }
0604 
0605 
0606 bool XMLUtil::ToFloat( const char* str, float* value )
0607 {
0608     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
0609         return true;
0610     }
0611     return false;
0612 }
0613 
0614 
0615 bool XMLUtil::ToDouble( const char* str, double* value )
0616 {
0617     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
0618         return true;
0619     }
0620     return false;
0621 }
0622 
0623 
0624 bool XMLUtil::ToInt64(const char* str, int64_t* value)
0625 {
0626     long long v = 0;    // horrible syntax trick to make the compiler happy about %lld

0627     if (TIXML_SSCANF(str, "%lld", &v) == 1) {
0628         *value = (int64_t)v;
0629         return true;
0630     }
0631     return false;
0632 }
0633 
0634 
0635 char* XMLDocument::Identify( char* p, XMLNode** node )
0636 {
0637     TIXMLASSERT( node );
0638     TIXMLASSERT( p );
0639     char* const start = p;
0640     p = XMLUtil::SkipWhiteSpace( p );
0641     if( !*p ) {
0642         *node = 0;
0643         TIXMLASSERT( p );
0644         return p;
0645     }
0646 
0647     // These strings define the matching patterns:

0648     static const char* xmlHeader        = { "<?" };
0649     static const char* commentHeader    = { "<!--" };
0650     static const char* cdataHeader      = { "<![CDATA[" };
0651     static const char* dtdHeader        = { "<!" };
0652     static const char* elementHeader    = { "<" };  // and a header for everything else; check last.

0653 
0654     static const int xmlHeaderLen       = 2;
0655     static const int commentHeaderLen   = 4;
0656     static const int cdataHeaderLen     = 9;
0657     static const int dtdHeaderLen       = 2;
0658     static const int elementHeaderLen   = 1;
0659 
0660     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool

0661     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool

0662     XMLNode* returnNode = 0;
0663     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
0664         TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
0665         returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
0666         returnNode->_memPool = &_commentPool;
0667         p += xmlHeaderLen;
0668     }
0669     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
0670         TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
0671         returnNode = new (_commentPool.Alloc()) XMLComment( this );
0672         returnNode->_memPool = &_commentPool;
0673         p += commentHeaderLen;
0674     }
0675     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
0676         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
0677         XMLText* text = new (_textPool.Alloc()) XMLText( this );
0678         returnNode = text;
0679         returnNode->_memPool = &_textPool;
0680         p += cdataHeaderLen;
0681         text->SetCData( true );
0682     }
0683     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
0684         TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
0685         returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
0686         returnNode->_memPool = &_commentPool;
0687         p += dtdHeaderLen;
0688     }
0689     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
0690         TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
0691         returnNode = new (_elementPool.Alloc()) XMLElement( this );
0692         returnNode->_memPool = &_elementPool;
0693         p += elementHeaderLen;
0694     }
0695     else {
0696         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
0697         returnNode = new (_textPool.Alloc()) XMLText( this );
0698         returnNode->_memPool = &_textPool;
0699         p = start;  // Back it up, all the text counts.

0700     }
0701 
0702     TIXMLASSERT( returnNode );
0703     TIXMLASSERT( p );
0704     *node = returnNode;
0705     return p;
0706 }
0707 
0708 
0709 bool XMLDocument::Accept( XMLVisitor* visitor ) const
0710 {
0711     TIXMLASSERT( visitor );
0712     if ( visitor->VisitEnter( *this ) ) {
0713         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
0714             if ( !node->Accept( visitor ) ) {
0715                 break;
0716             }
0717         }
0718     }
0719     return visitor->VisitExit( *this );
0720 }
0721 
0722 
0723 // --------- XMLNode ----------- //

0724 
0725 XMLNode::XMLNode( XMLDocument* doc ) :
0726     _document( doc ),
0727     _parent( 0 ),
0728     _firstChild( 0 ), _lastChild( 0 ),
0729     _prev( 0 ), _next( 0 ),
0730     _userData( 0 ),
0731     _memPool( 0 )
0732 {
0733 }
0734 
0735 
0736 XMLNode::~XMLNode()
0737 {
0738     DeleteChildren();
0739     if ( _parent ) {
0740         _parent->Unlink( this );
0741     }
0742 }
0743 
0744 const char* XMLNode::Value() const 
0745 {
0746     // Edge case: XMLDocuments don't have a Value. Return null.

0747     if ( this->ToDocument() )
0748         return 0;
0749     return _value.GetStr();
0750 }
0751 
0752 void XMLNode::SetValue( const char* str, bool staticMem )
0753 {
0754     if ( staticMem ) {
0755         _value.SetInternedStr( str );
0756     }
0757     else {
0758         _value.SetStr( str );
0759     }
0760 }
0761 
0762 
0763 void XMLNode::DeleteChildren()
0764 {
0765     while( _firstChild ) {
0766         TIXMLASSERT( _lastChild );
0767         DeleteChild( _firstChild );
0768     }
0769     _firstChild = _lastChild = 0;
0770 }
0771 
0772 
0773 void XMLNode::Unlink( XMLNode* child )
0774 {
0775     TIXMLASSERT( child );
0776     TIXMLASSERT( child->_document == _document );
0777     TIXMLASSERT( child->_parent == this );
0778     if ( child == _firstChild ) {
0779         _firstChild = _firstChild->_next;
0780     }
0781     if ( child == _lastChild ) {
0782         _lastChild = _lastChild->_prev;
0783     }
0784 
0785     if ( child->_prev ) {
0786         child->_prev->_next = child->_next;
0787     }
0788     if ( child->_next ) {
0789         child->_next->_prev = child->_prev;
0790     }
0791     child->_parent = 0;
0792 }
0793 
0794 
0795 void XMLNode::DeleteChild( XMLNode* node )
0796 {
0797     TIXMLASSERT( node );
0798     TIXMLASSERT( node->_document == _document );
0799     TIXMLASSERT( node->_parent == this );
0800     Unlink( node );
0801     DeleteNode( node );
0802 }
0803 
0804 
0805 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
0806 {
0807     TIXMLASSERT( addThis );
0808     if ( addThis->_document != _document ) {
0809         TIXMLASSERT( false );
0810         return 0;
0811     }
0812     InsertChildPreamble( addThis );
0813 
0814     if ( _lastChild ) {
0815         TIXMLASSERT( _firstChild );
0816         TIXMLASSERT( _lastChild->_next == 0 );
0817         _lastChild->_next = addThis;
0818         addThis->_prev = _lastChild;
0819         _lastChild = addThis;
0820 
0821         addThis->_next = 0;
0822     }
0823     else {
0824         TIXMLASSERT( _firstChild == 0 );
0825         _firstChild = _lastChild = addThis;
0826 
0827         addThis->_prev = 0;
0828         addThis->_next = 0;
0829     }
0830     addThis->_parent = this;
0831     return addThis;
0832 }
0833 
0834 
0835 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
0836 {
0837     TIXMLASSERT( addThis );
0838     if ( addThis->_document != _document ) {
0839         TIXMLASSERT( false );
0840         return 0;
0841     }
0842     InsertChildPreamble( addThis );
0843 
0844     if ( _firstChild ) {
0845         TIXMLASSERT( _lastChild );
0846         TIXMLASSERT( _firstChild->_prev == 0 );
0847 
0848         _firstChild->_prev = addThis;
0849         addThis->_next = _firstChild;
0850         _firstChild = addThis;
0851 
0852         addThis->_prev = 0;
0853     }
0854     else {
0855         TIXMLASSERT( _lastChild == 0 );
0856         _firstChild = _lastChild = addThis;
0857 
0858         addThis->_prev = 0;
0859         addThis->_next = 0;
0860     }
0861     addThis->_parent = this;
0862     return addThis;
0863 }
0864 
0865 
0866 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
0867 {
0868     TIXMLASSERT( addThis );
0869     if ( addThis->_document != _document ) {
0870         TIXMLASSERT( false );
0871         return 0;
0872     }
0873 
0874     TIXMLASSERT( afterThis );
0875 
0876     if ( afterThis->_parent != this ) {
0877         TIXMLASSERT( false );
0878         return 0;
0879     }
0880 
0881     if ( afterThis->_next == 0 ) {
0882         // The last node or the only node.

0883         return InsertEndChild( addThis );
0884     }
0885     InsertChildPreamble( addThis );
0886     addThis->_prev = afterThis;
0887     addThis->_next = afterThis->_next;
0888     afterThis->_next->_prev = addThis;
0889     afterThis->_next = addThis;
0890     addThis->_parent = this;
0891     return addThis;
0892 }
0893 
0894 
0895 
0896 
0897 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
0898 {
0899     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
0900         const XMLElement* element = node->ToElementWithName( name );
0901         if ( element ) {
0902             return element;
0903         }
0904     }
0905     return 0;
0906 }
0907 
0908 
0909 const XMLElement* XMLNode::LastChildElement( const char* name ) const
0910 {
0911     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
0912         const XMLElement* element = node->ToElementWithName( name );
0913         if ( element ) {
0914             return element;
0915         }
0916     }
0917     return 0;
0918 }
0919 
0920 
0921 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
0922 {
0923     for( const XMLNode* node = _next; node; node = node->_next ) {
0924         const XMLElement* element = node->ToElementWithName( name );
0925         if ( element ) {
0926             return element;
0927         }
0928     }
0929     return 0;
0930 }
0931 
0932 
0933 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
0934 {
0935     for( const XMLNode* node = _prev; node; node = node->_prev ) {
0936         const XMLElement* element = node->ToElementWithName( name );
0937         if ( element ) {
0938             return element;
0939         }
0940     }
0941     return 0;
0942 }
0943 
0944 
0945 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
0946 {
0947     // This is a recursive method, but thinking about it "at the current level"

0948     // it is a pretty simple flat list:

0949     //      <foo/>

0950     //      <!-- comment -->

0951     //

0952     // With a special case:

0953     //      <foo>

0954     //      </foo>

0955     //      <!-- comment -->

0956     //

0957     // Where the closing element (/foo) *must* be the next thing after the opening

0958     // element, and the names must match. BUT the tricky bit is that the closing

0959     // element will be read by the child.

0960     //

0961     // 'endTag' is the end tag for this node, it is returned by a call to a child.

0962     // 'parentEnd' is the end tag for the parent, which is filled in and returned.

0963 
0964     while( p && *p ) {
0965         XMLNode* node = 0;
0966 
0967         p = _document->Identify( p, &node );
0968         TIXMLASSERT( p );
0969         if ( node == 0 ) {
0970             break;
0971         }
0972 
0973         StrPair endTag;
0974         p = node->ParseDeep( p, &endTag );
0975         if ( !p ) {
0976             DeleteNode( node );
0977             if ( !_document->Error() ) {
0978                 _document->SetError( XML_ERROR_PARSING, 0, 0 );
0979             }
0980             break;
0981         }
0982 
0983         XMLDeclaration* decl = node->ToDeclaration();
0984         if ( decl ) {
0985             // Declarations are only allowed at document level

0986             bool wellLocated = ( ToDocument() != 0 );
0987             if ( wellLocated ) {
0988                 // Multiple declarations are allowed but all declarations

0989                 // must occur before anything else

0990                 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
0991                     if ( !existingNode->ToDeclaration() ) {
0992                         wellLocated = false;
0993                         break;
0994                     }
0995                 }
0996             }
0997             if ( !wellLocated ) {
0998                 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0 );
0999                 DeleteNode( node );
1000                 break;
1001             }
1002         }
1003 
1004         XMLElement* ele = node->ToElement();
1005         if ( ele ) {
1006             // We read the end tag. Return it to the parent.

1007             if ( ele->ClosingType() == XMLElement::CLOSING ) {
1008                 if ( parentEnd ) {
1009                     ele->_value.TransferTo( parentEnd );
1010                 }
1011                 node->_memPool->SetTracked();   // created and then immediately deleted.

1012                 DeleteNode( node );
1013                 return p;
1014             }
1015 
1016             // Handle an end tag returned to this level.

1017             // And handle a bunch of annoying errors.

1018             bool mismatch = false;
1019             if ( endTag.Empty() ) {
1020                 if ( ele->ClosingType() == XMLElement::OPEN ) {
1021                     mismatch = true;
1022                 }
1023             }
1024             else {
1025                 if ( ele->ClosingType() != XMLElement::OPEN ) {
1026                     mismatch = true;
1027                 }
1028                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1029                     mismatch = true;
1030                 }
1031             }
1032             if ( mismatch ) {
1033                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
1034                 DeleteNode( node );
1035                 break;
1036             }
1037         }
1038         InsertEndChild( node );
1039     }
1040     return 0;
1041 }
1042 
1043 void XMLNode::DeleteNode( XMLNode* node )
1044 {
1045     if ( node == 0 ) {
1046         return;
1047     }
1048     MemPool* pool = node->_memPool;
1049     node->~XMLNode();
1050     pool->Free( node );
1051 }
1052 
1053 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1054 {
1055     TIXMLASSERT( insertThis );
1056     TIXMLASSERT( insertThis->_document == _document );
1057 
1058     if ( insertThis->_parent )
1059         insertThis->_parent->Unlink( insertThis );
1060     else
1061         insertThis->_memPool->SetTracked();
1062 }
1063 
1064 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1065 {
1066     const XMLElement* element = this->ToElement();
1067     if ( element == 0 ) {
1068         return 0;
1069     }
1070     if ( name == 0 ) {
1071         return element;
1072     }
1073     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1074        return element;
1075     }
1076     return 0;
1077 }
1078 
1079 // --------- XMLText ---------- //

1080 char* XMLText::ParseDeep( char* p, StrPair* )
1081 {
1082     const char* start = p;
1083     if ( this->CData() ) {
1084         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1085         if ( !p ) {
1086             _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
1087         }
1088         return p;
1089     }
1090     else {
1091         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1092         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1093             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1094         }
1095 
1096         p = _value.ParseText( p, "<", flags );
1097         if ( p && *p ) {
1098             return p-1;
1099         }
1100         if ( !p ) {
1101             _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
1102         }
1103     }
1104     return 0;
1105 }
1106 
1107 
1108 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1109 {
1110     if ( !doc ) {
1111         doc = _document;
1112     }
1113     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?

1114     text->SetCData( this->CData() );
1115     return text;
1116 }
1117 
1118 
1119 bool XMLText::ShallowEqual( const XMLNode* compare ) const
1120 {
1121     const XMLText* text = compare->ToText();
1122     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1123 }
1124 
1125 
1126 bool XMLText::Accept( XMLVisitor* visitor ) const
1127 {
1128     TIXMLASSERT( visitor );
1129     return visitor->Visit( *this );
1130 }
1131 
1132 
1133 // --------- XMLComment ---------- //

1134 
1135 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1136 {
1137 }
1138 
1139 
1140 XMLComment::~XMLComment()
1141 {
1142 }
1143 
1144 
1145 char* XMLComment::ParseDeep( char* p, StrPair* )
1146 {
1147     // Comment parses as text.

1148     const char* start = p;
1149     p = _value.ParseText( p, "-->", StrPair::COMMENT );
1150     if ( p == 0 ) {
1151         _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
1152     }
1153     return p;
1154 }
1155 
1156 
1157 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1158 {
1159     if ( !doc ) {
1160         doc = _document;
1161     }
1162     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?

1163     return comment;
1164 }
1165 
1166 
1167 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1168 {
1169     TIXMLASSERT( compare );
1170     const XMLComment* comment = compare->ToComment();
1171     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1172 }
1173 
1174 
1175 bool XMLComment::Accept( XMLVisitor* visitor ) const
1176 {
1177     TIXMLASSERT( visitor );
1178     return visitor->Visit( *this );
1179 }
1180 
1181 
1182 // --------- XMLDeclaration ---------- //

1183 
1184 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1185 {
1186 }
1187 
1188 
1189 XMLDeclaration::~XMLDeclaration()
1190 {
1191     //printf( "~XMLDeclaration\n" );

1192 }
1193 
1194 
1195 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
1196 {
1197     // Declaration parses as text.

1198     const char* start = p;
1199     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1200     if ( p == 0 ) {
1201         _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
1202     }
1203     return p;
1204 }
1205 
1206 
1207 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1208 {
1209     if ( !doc ) {
1210         doc = _document;
1211     }
1212     XMLDeclaration* dec = doc->NewDeclaration( Value() );   // fixme: this will always allocate memory. Intern?

1213     return dec;
1214 }
1215 
1216 
1217 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1218 {
1219     TIXMLASSERT( compare );
1220     const XMLDeclaration* declaration = compare->ToDeclaration();
1221     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1222 }
1223 
1224 
1225 
1226 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1227 {
1228     TIXMLASSERT( visitor );
1229     return visitor->Visit( *this );
1230 }
1231 
1232 // --------- XMLUnknown ---------- //

1233 
1234 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1235 {
1236 }
1237 
1238 
1239 XMLUnknown::~XMLUnknown()
1240 {
1241 }
1242 
1243 
1244 char* XMLUnknown::ParseDeep( char* p, StrPair* )
1245 {
1246     // Unknown parses as text.

1247     const char* start = p;
1248 
1249     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1250     if ( !p ) {
1251         _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
1252     }
1253     return p;
1254 }
1255 
1256 
1257 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1258 {
1259     if ( !doc ) {
1260         doc = _document;
1261     }
1262     XMLUnknown* text = doc->NewUnknown( Value() );  // fixme: this will always allocate memory. Intern?

1263     return text;
1264 }
1265 
1266 
1267 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1268 {
1269     TIXMLASSERT( compare );
1270     const XMLUnknown* unknown = compare->ToUnknown();
1271     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1272 }
1273 
1274 
1275 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1276 {
1277     TIXMLASSERT( visitor );
1278     return visitor->Visit( *this );
1279 }
1280 
1281 // --------- XMLAttribute ---------- //

1282 
1283 const char* XMLAttribute::Name() const 
1284 {
1285     return _name.GetStr();
1286 }
1287 
1288 const char* XMLAttribute::Value() const 
1289 {
1290     return _value.GetStr();
1291 }
1292 
1293 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
1294 {
1295     // Parse using the name rules: bug fix, was using ParseText before

1296     p = _name.ParseName( p );
1297     if ( !p || !*p ) {
1298         return 0;
1299     }
1300 
1301     // Skip white space before =

1302     p = XMLUtil::SkipWhiteSpace( p );
1303     if ( *p != '=' ) {
1304         return 0;
1305     }
1306 
1307     ++p;    // move up to opening quote

1308     p = XMLUtil::SkipWhiteSpace( p );
1309     if ( *p != '\"' && *p != '\'' ) {
1310         return 0;
1311     }
1312 
1313     char endTag[2] = { *p, 0 };
1314     ++p;    // move past opening quote

1315 
1316     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1317     return p;
1318 }
1319 
1320 
1321 void XMLAttribute::SetName( const char* n )
1322 {
1323     _name.SetStr( n );
1324 }
1325 
1326 
1327 XMLError XMLAttribute::QueryIntValue( int* value ) const
1328 {
1329     if ( XMLUtil::ToInt( Value(), value )) {
1330         return XML_SUCCESS;
1331     }
1332     return XML_WRONG_ATTRIBUTE_TYPE;
1333 }
1334 
1335 
1336 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1337 {
1338     if ( XMLUtil::ToUnsigned( Value(), value )) {
1339         return XML_SUCCESS;
1340     }
1341     return XML_WRONG_ATTRIBUTE_TYPE;
1342 }
1343 
1344 
1345 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1346 {
1347     if (XMLUtil::ToInt64(Value(), value)) {
1348         return XML_SUCCESS;
1349     }
1350     return XML_WRONG_ATTRIBUTE_TYPE;
1351 }
1352 
1353 
1354 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1355 {
1356     if ( XMLUtil::ToBool( Value(), value )) {
1357         return XML_SUCCESS;
1358     }
1359     return XML_WRONG_ATTRIBUTE_TYPE;
1360 }
1361 
1362 
1363 XMLError XMLAttribute::QueryFloatValue( float* value ) const
1364 {
1365     if ( XMLUtil::ToFloat( Value(), value )) {
1366         return XML_SUCCESS;
1367     }
1368     return XML_WRONG_ATTRIBUTE_TYPE;
1369 }
1370 
1371 
1372 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1373 {
1374     if ( XMLUtil::ToDouble( Value(), value )) {
1375         return XML_SUCCESS;
1376     }
1377     return XML_WRONG_ATTRIBUTE_TYPE;
1378 }
1379 
1380 
1381 void XMLAttribute::SetAttribute( const char* v )
1382 {
1383     _value.SetStr( v );
1384 }
1385 
1386 
1387 void XMLAttribute::SetAttribute( int v )
1388 {
1389     char buf[BUF_SIZE];
1390     XMLUtil::ToStr( v, buf, BUF_SIZE );
1391     _value.SetStr( buf );
1392 }
1393 
1394 
1395 void XMLAttribute::SetAttribute( unsigned v )
1396 {
1397     char buf[BUF_SIZE];
1398     XMLUtil::ToStr( v, buf, BUF_SIZE );
1399     _value.SetStr( buf );
1400 }
1401 
1402 
1403 void XMLAttribute::SetAttribute(int64_t v)
1404 {
1405     char buf[BUF_SIZE];
1406     XMLUtil::ToStr(v, buf, BUF_SIZE);
1407     _value.SetStr(buf);
1408 }
1409 
1410 
1411 
1412 void XMLAttribute::SetAttribute( bool v )
1413 {
1414     char buf[BUF_SIZE];
1415     XMLUtil::ToStr( v, buf, BUF_SIZE );
1416     _value.SetStr( buf );
1417 }
1418 
1419 void XMLAttribute::SetAttribute( double v )
1420 {
1421     char buf[BUF_SIZE];
1422     XMLUtil::ToStr( v, buf, BUF_SIZE );
1423     _value.SetStr( buf );
1424 }
1425 
1426 void XMLAttribute::SetAttribute( float v )
1427 {
1428     char buf[BUF_SIZE];
1429     XMLUtil::ToStr( v, buf, BUF_SIZE );
1430     _value.SetStr( buf );
1431 }
1432 
1433 
1434 // --------- XMLElement ---------- //

1435 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1436     _closingType( 0 ),
1437     _rootAttribute( 0 )
1438 {
1439 }
1440 
1441 
1442 XMLElement::~XMLElement()
1443 {
1444     while( _rootAttribute ) {
1445         XMLAttribute* next = _rootAttribute->_next;
1446         DeleteAttribute( _rootAttribute );
1447         _rootAttribute = next;
1448     }
1449 }
1450 
1451 
1452 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1453 {
1454     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1455         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1456             return a;
1457         }
1458     }
1459     return 0;
1460 }
1461 
1462 
1463 const char* XMLElement::Attribute( const char* name, const char* value ) const
1464 {
1465     const XMLAttribute* a = FindAttribute( name );
1466     if ( !a ) {
1467         return 0;
1468     }
1469     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1470         return a->Value();
1471     }
1472     return 0;
1473 }
1474 
1475 int XMLElement::IntAttribute(const char* name, int defaultValue) const 
1476 {
1477     int i = defaultValue;
1478     QueryIntAttribute(name, &i);
1479     return i;
1480 }
1481 
1482 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const 
1483 {
1484     unsigned i = defaultValue;
1485     QueryUnsignedAttribute(name, &i);
1486     return i;
1487 }
1488 
1489 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const 
1490 {
1491     int64_t i = defaultValue;
1492     QueryInt64Attribute(name, &i);
1493     return i;
1494 }
1495 
1496 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const 
1497 {
1498     bool b = defaultValue;
1499     QueryBoolAttribute(name, &b);
1500     return b;
1501 }
1502 
1503 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const 
1504 {
1505     double d = defaultValue;
1506     QueryDoubleAttribute(name, &d);
1507     return d;
1508 }
1509 
1510 float XMLElement::FloatAttribute(const char* name, float defaultValue) const 
1511 {
1512     float f = defaultValue;
1513     QueryFloatAttribute(name, &f);
1514     return f;
1515 }
1516 
1517 const char* XMLElement::GetText() const
1518 {
1519     if ( FirstChild() && FirstChild()->ToText() ) {
1520         return FirstChild()->Value();
1521     }
1522     return 0;
1523 }
1524 
1525 
1526 void    XMLElement::SetText( const char* inText )
1527 {
1528     if ( FirstChild() && FirstChild()->ToText() )
1529         FirstChild()->SetValue( inText );
1530     else {
1531         XMLText*    theText = GetDocument()->NewText( inText );
1532         InsertFirstChild( theText );
1533     }
1534 }
1535 
1536 
1537 void XMLElement::SetText( int v ) 
1538 {
1539     char buf[BUF_SIZE];
1540     XMLUtil::ToStr( v, buf, BUF_SIZE );
1541     SetText( buf );
1542 }
1543 
1544 
1545 void XMLElement::SetText( unsigned v ) 
1546 {
1547     char buf[BUF_SIZE];
1548     XMLUtil::ToStr( v, buf, BUF_SIZE );
1549     SetText( buf );
1550 }
1551 
1552 
1553 void XMLElement::SetText(int64_t v)
1554 {
1555     char buf[BUF_SIZE];
1556     XMLUtil::ToStr(v, buf, BUF_SIZE);
1557     SetText(buf);
1558 }
1559 
1560 
1561 void XMLElement::SetText( bool v )
1562 {
1563     char buf[BUF_SIZE];
1564     XMLUtil::ToStr( v, buf, BUF_SIZE );
1565     SetText( buf );
1566 }
1567 
1568 
1569 void XMLElement::SetText( float v ) 
1570 {
1571     char buf[BUF_SIZE];
1572     XMLUtil::ToStr( v, buf, BUF_SIZE );
1573     SetText( buf );
1574 }
1575 
1576 
1577 void XMLElement::SetText( double v ) 
1578 {
1579     char buf[BUF_SIZE];
1580     XMLUtil::ToStr( v, buf, BUF_SIZE );
1581     SetText( buf );
1582 }
1583 
1584 
1585 XMLError XMLElement::QueryIntText( int* ival ) const
1586 {
1587     if ( FirstChild() && FirstChild()->ToText() ) {
1588         const char* t = FirstChild()->Value();
1589         if ( XMLUtil::ToInt( t, ival ) ) {
1590             return XML_SUCCESS;
1591         }
1592         return XML_CAN_NOT_CONVERT_TEXT;
1593     }
1594     return XML_NO_TEXT_NODE;
1595 }
1596 
1597 
1598 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1599 {
1600     if ( FirstChild() && FirstChild()->ToText() ) {
1601         const char* t = FirstChild()->Value();
1602         if ( XMLUtil::ToUnsigned( t, uval ) ) {
1603             return XML_SUCCESS;
1604         }
1605         return XML_CAN_NOT_CONVERT_TEXT;
1606     }
1607     return XML_NO_TEXT_NODE;
1608 }
1609 
1610 
1611 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1612 {
1613     if (FirstChild() && FirstChild()->ToText()) {
1614         const char* t = FirstChild()->Value();
1615         if (XMLUtil::ToInt64(t, ival)) {
1616             return XML_SUCCESS;
1617         }
1618         return XML_CAN_NOT_CONVERT_TEXT;
1619     }
1620     return XML_NO_TEXT_NODE;
1621 }
1622 
1623 
1624 XMLError XMLElement::QueryBoolText( bool* bval ) const
1625 {
1626     if ( FirstChild() && FirstChild()->ToText() ) {
1627         const char* t = FirstChild()->Value();
1628         if ( XMLUtil::ToBool( t, bval ) ) {
1629             return XML_SUCCESS;
1630         }
1631         return XML_CAN_NOT_CONVERT_TEXT;
1632     }
1633     return XML_NO_TEXT_NODE;
1634 }
1635 
1636 
1637 XMLError XMLElement::QueryDoubleText( double* dval ) const
1638 {
1639     if ( FirstChild() && FirstChild()->ToText() ) {
1640         const char* t = FirstChild()->Value();
1641         if ( XMLUtil::ToDouble( t, dval ) ) {
1642             return XML_SUCCESS;
1643         }
1644         return XML_CAN_NOT_CONVERT_TEXT;
1645     }
1646     return XML_NO_TEXT_NODE;
1647 }
1648 
1649 
1650 XMLError XMLElement::QueryFloatText( float* fval ) const
1651 {
1652     if ( FirstChild() && FirstChild()->ToText() ) {
1653         const char* t = FirstChild()->Value();
1654         if ( XMLUtil::ToFloat( t, fval ) ) {
1655             return XML_SUCCESS;
1656         }
1657         return XML_CAN_NOT_CONVERT_TEXT;
1658     }
1659     return XML_NO_TEXT_NODE;
1660 }
1661 
1662 int XMLElement::IntText(int defaultValue) const
1663 {
1664     int i = defaultValue;
1665     QueryIntText(&i);
1666     return i;
1667 }
1668 
1669 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1670 {
1671     unsigned i = defaultValue;
1672     QueryUnsignedText(&i);
1673     return i;
1674 }
1675 
1676 int64_t XMLElement::Int64Text(int64_t defaultValue) const
1677 {
1678     int64_t i = defaultValue;
1679     QueryInt64Text(&i);
1680     return i;
1681 }
1682 
1683 bool XMLElement::BoolText(bool defaultValue) const
1684 {
1685     bool b = defaultValue;
1686     QueryBoolText(&b);
1687     return b;
1688 }
1689 
1690 double XMLElement::DoubleText(double defaultValue) const
1691 {
1692     double d = defaultValue;
1693     QueryDoubleText(&d);
1694     return d;
1695 }
1696 
1697 float XMLElement::FloatText(float defaultValue) const
1698 {
1699     float f = defaultValue;
1700     QueryFloatText(&f);
1701     return f;
1702 }
1703 
1704 
1705 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1706 {
1707     XMLAttribute* last = 0;
1708     XMLAttribute* attrib = 0;
1709     for( attrib = _rootAttribute;
1710             attrib;
1711             last = attrib, attrib = attrib->_next ) {
1712         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1713             break;
1714         }
1715     }
1716     if ( !attrib ) {
1717         attrib = CreateAttribute();
1718         TIXMLASSERT( attrib );
1719         if ( last ) {
1720             last->_next = attrib;
1721         }
1722         else {
1723             _rootAttribute = attrib;
1724         }
1725         attrib->SetName( name );
1726     }
1727     return attrib;
1728 }
1729 
1730 
1731 void XMLElement::DeleteAttribute( const char* name )
1732 {
1733     XMLAttribute* prev = 0;
1734     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1735         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1736             if ( prev ) {
1737                 prev->_next = a->_next;
1738             }
1739             else {
1740                 _rootAttribute = a->_next;
1741             }
1742             DeleteAttribute( a );
1743             break;
1744         }
1745         prev = a;
1746     }
1747 }
1748 
1749 
1750 char* XMLElement::ParseAttributes( char* p )
1751 {
1752     const char* start = p;
1753     XMLAttribute* prevAttribute = 0;
1754 
1755     // Read the attributes.

1756     while( p ) {
1757         p = XMLUtil::SkipWhiteSpace( p );
1758         if ( !(*p) ) {
1759             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
1760             return 0;
1761         }
1762 
1763         // attribute.

1764         if (XMLUtil::IsNameStartChar( *p ) ) {
1765             XMLAttribute* attrib = CreateAttribute();
1766             TIXMLASSERT( attrib );
1767 
1768             p = attrib->ParseDeep( p, _document->ProcessEntities() );
1769             if ( !p || Attribute( attrib->Name() ) ) {
1770                 DeleteAttribute( attrib );
1771                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1772                 return 0;
1773             }
1774             // There is a minor bug here: if the attribute in the source xml

1775             // document is duplicated, it will not be detected and the

1776             // attribute will be doubly added. However, tracking the 'prevAttribute'

1777             // avoids re-scanning the attribute list. Preferring performance for

1778             // now, may reconsider in the future.

1779             if ( prevAttribute ) {
1780                 prevAttribute->_next = attrib;
1781             }
1782             else {
1783                 _rootAttribute = attrib;
1784             }
1785             prevAttribute = attrib;
1786         }
1787         // end of the tag

1788         else if ( *p == '>' ) {
1789             ++p;
1790             break;
1791         }
1792         // end of the tag

1793         else if ( *p == '/' && *(p+1) == '>' ) {
1794             _closingType = CLOSED;
1795             return p+2; // done; sealed element.

1796         }
1797         else {
1798             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1799             return 0;
1800         }
1801     }
1802     return p;
1803 }
1804 
1805 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1806 {
1807     if ( attribute == 0 ) {
1808         return;
1809     }
1810     MemPool* pool = attribute->_memPool;
1811     attribute->~XMLAttribute();
1812     pool->Free( attribute );
1813 }
1814 
1815 XMLAttribute* XMLElement::CreateAttribute()
1816 {
1817     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1818     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1819     attrib->_memPool = &_document->_attributePool;
1820     attrib->_memPool->SetTracked();
1821     return attrib;
1822 }
1823 
1824 //

1825 //  <ele></ele>

1826 //  <ele>foo<b>bar</b></ele>

1827 //

1828 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
1829 {
1830     // Read the element name.

1831     p = XMLUtil::SkipWhiteSpace( p );
1832 
1833     // The closing element is the </element> form. It is

1834     // parsed just like a regular element then deleted from

1835     // the DOM.

1836     if ( *p == '/' ) {
1837         _closingType = CLOSING;
1838         ++p;
1839     }
1840 
1841     p = _value.ParseName( p );
1842     if ( _value.Empty() ) {
1843         return 0;
1844     }
1845 
1846     p = ParseAttributes( p );
1847     if ( !p || !*p || _closingType ) {
1848         return p;
1849     }
1850 
1851     p = XMLNode::ParseDeep( p, strPair );
1852     return p;
1853 }
1854 
1855 
1856 
1857 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1858 {
1859     if ( !doc ) {
1860         doc = _document;
1861     }
1862     XMLElement* element = doc->NewElement( Value() );                   // fixme: this will always allocate memory. Intern?

1863     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1864         element->SetAttribute( a->Name(), a->Value() );                 // fixme: this will always allocate memory. Intern?

1865     }
1866     return element;
1867 }
1868 
1869 
1870 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1871 {
1872     TIXMLASSERT( compare );
1873     const XMLElement* other = compare->ToElement();
1874     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
1875 
1876         const XMLAttribute* a=FirstAttribute();
1877         const XMLAttribute* b=other->FirstAttribute();
1878 
1879         while ( a && b ) {
1880             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1881                 return false;
1882             }
1883             a = a->Next();
1884             b = b->Next();
1885         }
1886         if ( a || b ) {
1887             // different count

1888             return false;
1889         }
1890         return true;
1891     }
1892     return false;
1893 }
1894 
1895 
1896 bool XMLElement::Accept( XMLVisitor* visitor ) const
1897 {
1898     TIXMLASSERT( visitor );
1899     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
1900         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1901             if ( !node->Accept( visitor ) ) {
1902                 break;
1903             }
1904         }
1905     }
1906     return visitor->VisitExit( *this );
1907 }
1908 
1909 
1910 // --------- XMLDocument ----------- //

1911 
1912 // Warning: List must match 'enum XMLError'

1913 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1914     "XML_SUCCESS",
1915     "XML_NO_ATTRIBUTE",
1916     "XML_WRONG_ATTRIBUTE_TYPE",
1917     "XML_ERROR_FILE_NOT_FOUND",
1918     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1919     "XML_ERROR_FILE_READ_ERROR",
1920     "XML_ERROR_ELEMENT_MISMATCH",
1921     "XML_ERROR_PARSING_ELEMENT",
1922     "XML_ERROR_PARSING_ATTRIBUTE",
1923     "XML_ERROR_IDENTIFYING_TAG",
1924     "XML_ERROR_PARSING_TEXT",
1925     "XML_ERROR_PARSING_CDATA",
1926     "XML_ERROR_PARSING_COMMENT",
1927     "XML_ERROR_PARSING_DECLARATION",
1928     "XML_ERROR_PARSING_UNKNOWN",
1929     "XML_ERROR_EMPTY_DOCUMENT",
1930     "XML_ERROR_MISMATCHED_ELEMENT",
1931     "XML_ERROR_PARSING",
1932     "XML_CAN_NOT_CONVERT_TEXT",
1933     "XML_NO_TEXT_NODE"
1934 };
1935 
1936 
1937 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
1938     XMLNode( 0 ),
1939     _writeBOM( false ),
1940     _processEntities( processEntities ),
1941     _errorID(XML_SUCCESS),
1942     _whitespace( whitespace ),
1943     _charBuffer( 0 )
1944 {
1945     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)

1946     _document = this;
1947 }
1948 
1949 
1950 XMLDocument::~XMLDocument()
1951 {
1952     Clear();
1953 }
1954 
1955 
1956 void XMLDocument::Clear()
1957 {
1958     DeleteChildren();
1959 
1960 #ifdef DEBUG
1961     const bool hadError = Error();
1962 #endif
1963     ClearError();
1964 
1965     delete [] _charBuffer;
1966     _charBuffer = 0;
1967 
1968 #if 0
1969     _textPool.Trace( "text" );
1970     _elementPool.Trace( "element" );
1971     _commentPool.Trace( "comment" );
1972     _attributePool.Trace( "attribute" );
1973 #endif
1974     
1975 #ifdef DEBUG
1976     if ( !hadError ) {
1977         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
1978         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1979         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
1980         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
1981     }
1982 #endif
1983 }
1984 
1985 
1986 XMLElement* XMLDocument::NewElement( const char* name )
1987 {
1988     TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
1989     XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1990     ele->_memPool = &_elementPool;
1991     ele->SetName( name );
1992     return ele;
1993 }
1994 
1995 
1996 XMLComment* XMLDocument::NewComment( const char* str )
1997 {
1998     TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
1999     XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
2000     comment->_memPool = &_commentPool;
2001     comment->SetValue( str );
2002     return comment;
2003 }
2004 
2005 
2006 XMLText* XMLDocument::NewText( const char* str )
2007 {
2008     TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
2009     XMLText* text = new (_textPool.Alloc()) XMLText( this );
2010     text->_memPool = &_textPool;
2011     text->SetValue( str );
2012     return text;
2013 }
2014 
2015 
2016 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2017 {
2018     TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
2019     XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2020     dec->_memPool = &_commentPool;
2021     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2022     return dec;
2023 }
2024 
2025 
2026 XMLUnknown* XMLDocument::NewUnknown( const char* str )
2027 {
2028     TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
2029     XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2030     unk->_memPool = &_commentPool;
2031     unk->SetValue( str );
2032     return unk;
2033 }
2034 
2035 static FILE* callfopen( const char* filepath, const char* mode )
2036 {
2037     TIXMLASSERT( filepath );
2038     TIXMLASSERT( mode );
2039 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2040     FILE* fp = 0;
2041     errno_t err = fopen_s( &fp, filepath, mode );
2042     if ( err ) {
2043         return 0;
2044     }
2045 #else
2046     FILE* fp = fopen( filepath, mode );
2047 #endif
2048     return fp;
2049 }
2050     
2051 void XMLDocument::DeleteNode( XMLNode* node )   {
2052     TIXMLASSERT( node );
2053     TIXMLASSERT(node->_document == this );
2054     if (node->_parent) {
2055         node->_parent->DeleteChild( node );
2056     }
2057     else {
2058         // Isn't in the tree.

2059         // Use the parent delete.

2060         // Also, we need to mark it tracked: we 'know'

2061         // it was never used.

2062         node->_memPool->SetTracked();
2063         // Call the static XMLNode version:

2064         XMLNode::DeleteNode(node);
2065     }
2066 }
2067 
2068 
2069 XMLError XMLDocument::LoadFile( const char* filename )
2070 {
2071     Clear();
2072     FILE* fp = callfopen( filename, "rb" );
2073     if ( !fp ) {
2074         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
2075         return _errorID;
2076     }
2077     LoadFile( fp );
2078     fclose( fp );
2079     return _errorID;
2080 }
2081 
2082 // This is likely overengineered template art to have a check that unsigned long value incremented

2083 // by one still fits into size_t. If size_t type is larger than unsigned long type

2084 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit

2085 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check

2086 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long

2087 // types sizes relate to each other.

2088 template
2089 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
2090 struct LongFitsIntoSizeTMinusOne {
2091     static bool Fits( unsigned long value )
2092     {
2093         return value < (size_t)-1;
2094     }
2095 };
2096 
2097 template <>
2098 struct LongFitsIntoSizeTMinusOne<false> {
2099     static bool Fits( unsigned long )
2100     {
2101         return true;
2102     }
2103 };
2104 
2105 XMLError XMLDocument::LoadFile( FILE* fp )
2106 {
2107     Clear();
2108 
2109     fseek( fp, 0, SEEK_SET );
2110     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2111         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2112         return _errorID;
2113     }
2114 
2115     fseek( fp, 0, SEEK_END );
2116     const long filelength = ftell( fp );
2117     fseek( fp, 0, SEEK_SET );
2118     if ( filelength == -1L ) {
2119         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2120         return _errorID;
2121     }
2122     TIXMLASSERT( filelength >= 0 );
2123 
2124     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
2125         // Cannot handle files which won't fit in buffer together with null terminator

2126         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2127         return _errorID;
2128     }
2129 
2130     if ( filelength == 0 ) {
2131         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2132         return _errorID;
2133     }
2134 
2135     const size_t size = filelength;
2136     TIXMLASSERT( _charBuffer == 0 );
2137     _charBuffer = new char[size+1];
2138     size_t read = fread( _charBuffer, 1, size, fp );
2139     if ( read != size ) {
2140         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2141         return _errorID;
2142     }
2143 
2144     _charBuffer[size] = 0;
2145 
2146     Parse();
2147     return _errorID;
2148 }
2149 
2150 
2151 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2152 {
2153     FILE* fp = callfopen( filename, "w" );
2154     if ( !fp ) {
2155         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
2156         return _errorID;
2157     }
2158     SaveFile(fp, compact);
2159     fclose( fp );
2160     return _errorID;
2161 }
2162 
2163 
2164 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2165 {
2166     // Clear any error from the last save, otherwise it will get reported

2167     // for *this* call.

2168     ClearError();
2169     XMLPrinter stream( fp, compact );
2170     Print( &stream );
2171     return _errorID;
2172 }
2173 
2174 
2175 XMLError XMLDocument::Parse( const char* p, size_t len )
2176 {
2177     Clear();
2178 
2179     if ( len == 0 || !p || !*p ) {
2180         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2181         return _errorID;
2182     }
2183     if ( len == (size_t)(-1) ) {
2184         len = strlen( p );
2185     }
2186     TIXMLASSERT( _charBuffer == 0 );
2187     _charBuffer = new char[ len+1 ];
2188     memcpy( _charBuffer, p, len );
2189     _charBuffer[len] = 0;
2190 
2191     Parse();
2192     if ( Error() ) {
2193         // clean up now essentially dangling memory.

2194         // and the parse fail can put objects in the

2195         // pools that are dead and inaccessible.

2196         DeleteChildren();
2197         _elementPool.Clear();
2198         _attributePool.Clear();
2199         _textPool.Clear();
2200         _commentPool.Clear();
2201     }
2202     return _errorID;
2203 }
2204 
2205 
2206 void XMLDocument::Print( XMLPrinter* streamer ) const
2207 {
2208     if ( streamer ) {
2209         Accept( streamer );
2210     }
2211     else {
2212         XMLPrinter stdoutStreamer( stdout );
2213         Accept( &stdoutStreamer );
2214     }
2215 }
2216 
2217 
2218 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
2219 {
2220     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2221     _errorID = error;
2222     
2223     _errorStr1.Reset();
2224     _errorStr2.Reset();
2225 
2226     if (str1)
2227         _errorStr1.SetStr(str1);
2228     if (str2)
2229         _errorStr2.SetStr(str2);
2230 }
2231 
2232 const char* XMLDocument::ErrorName() const
2233 {
2234     TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
2235     const char* errorName = _errorNames[_errorID];
2236     TIXMLASSERT( errorName && errorName[0] );
2237     return errorName;
2238 }
2239 
2240 void XMLDocument::PrintError() const
2241 {
2242     if ( Error() ) {
2243         static const int LEN = 20;
2244         char buf1[LEN] = { 0 };
2245         char buf2[LEN] = { 0 };
2246 
2247         if ( !_errorStr1.Empty() ) {
2248             TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
2249         }
2250         if ( !_errorStr2.Empty() ) {
2251             TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
2252         }
2253 
2254         // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that

2255         // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning

2256         TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
2257         printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
2258                 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
2259     }
2260 }
2261 
2262 void XMLDocument::Parse()
2263 {
2264     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously

2265     TIXMLASSERT( _charBuffer );
2266     char* p = _charBuffer;
2267     p = XMLUtil::SkipWhiteSpace( p );
2268     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2269     if ( !*p ) {
2270         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2271         return;
2272     }
2273     ParseDeep(p, 0 );
2274 }
2275 
2276 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2277     _elementJustOpened( false ),
2278     _firstElement( true ),
2279     _fp( file ),
2280     _depth( depth ),
2281     _textDepth( -1 ),
2282     _processEntities( true ),
2283     _compactMode( compact )
2284 {
2285     for( int i=0; i<ENTITY_RANGE; ++i ) {
2286         _entityFlag[i] = false;
2287         _restrictedEntityFlag[i] = false;
2288     }
2289     for( int i=0; i<NUM_ENTITIES; ++i ) {
2290         const char entityValue = entities[i].value;
2291         TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
2292         _entityFlag[ (unsigned char)entityValue ] = true;
2293     }
2294     _restrictedEntityFlag[(unsigned char)'&'] = true;
2295     _restrictedEntityFlag[(unsigned char)'<'] = true;
2296     _restrictedEntityFlag[(unsigned char)'>'] = true;   // not required, but consistency is nice

2297     _buffer.Push( 0 );
2298 }
2299 
2300 
2301 void XMLPrinter::Print( const char* format, ... )
2302 {
2303     va_list     va;
2304     va_start( va, format );
2305 
2306     if ( _fp ) {
2307         vfprintf( _fp, format, va );
2308     }
2309     else {
2310         const int len = TIXML_VSCPRINTF( format, va );
2311         // Close out and re-start the va-args

2312         va_end( va );
2313         TIXMLASSERT( len >= 0 );
2314         va_start( va, format );
2315         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2316         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.

2317         TIXML_VSNPRINTF( p, len+1, format, va );
2318     }
2319     va_end( va );
2320 }
2321 
2322 
2323 void XMLPrinter::PrintSpace( int depth )
2324 {
2325     for( int i=0; i<depth; ++i ) {
2326         Print( "    " );
2327     }
2328 }
2329 
2330 
2331 void XMLPrinter::PrintString( const char* p, bool restricted )
2332 {
2333     // Look for runs of bytes between entities to print.

2334     const char* q = p;
2335 
2336     if ( _processEntities ) {
2337         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2338         while ( *q ) {
2339             TIXMLASSERT( p <= q );
2340             // Remember, char is sometimes signed. (How many times has that bitten me?)

2341             if ( *q > 0 && *q < ENTITY_RANGE ) {
2342                 // Check for entities. If one is found, flush

2343                 // the stream up until the entity, write the

2344                 // entity, and keep looking.

2345                 if ( flag[(unsigned char)(*q)] ) {
2346                     while ( p < q ) {
2347                         const size_t delta = q - p;
2348                         // %.*s accepts type int as "precision"

2349                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2350                         Print( "%.*s", toPrint, p );
2351                         p += toPrint;
2352                     }
2353                     bool entityPatternPrinted = false;
2354                     for( int i=0; i<NUM_ENTITIES; ++i ) {
2355                         if ( entities[i].value == *q ) {
2356                             Print( "&%s;", entities[i].pattern );
2357                             entityPatternPrinted = true;
2358                             break;
2359                         }
2360                     }
2361                     if ( !entityPatternPrinted ) {
2362                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release

2363                         TIXMLASSERT( false );
2364                     }
2365                     ++p;
2366                 }
2367             }
2368             ++q;
2369             TIXMLASSERT( p <= q );
2370         }
2371     }
2372     // Flush the remaining string. This will be the entire

2373     // string if an entity wasn't found.

2374     TIXMLASSERT( p <= q );
2375     if ( !_processEntities || ( p < q ) ) {
2376         Print( "%s", p );
2377     }
2378 }
2379 
2380 
2381 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2382 {
2383     if ( writeBOM ) {
2384         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2385         Print( "%s", bom );
2386     }
2387     if ( writeDec ) {
2388         PushDeclaration( "xml version=\"1.0\"" );
2389     }
2390 }
2391 
2392 
2393 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2394 {
2395     SealElementIfJustOpened();
2396     _stack.Push( name );
2397 
2398     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
2399         Print( "\n" );
2400     }
2401     if ( !compactMode ) {
2402         PrintSpace( _depth );
2403     }
2404 
2405     Print( "<%s", name );
2406     _elementJustOpened = true;
2407     _firstElement = false;
2408     ++_depth;
2409 }
2410 
2411 
2412 void XMLPrinter::PushAttribute( const char* name, const char* value )
2413 {
2414     TIXMLASSERT( _elementJustOpened );
2415     Print( " %s=\"", name );
2416     PrintString( value, false );
2417     Print( "\"" );
2418 }
2419 
2420 
2421 void XMLPrinter::PushAttribute( const char* name, int v )
2422 {
2423     char buf[BUF_SIZE];
2424     XMLUtil::ToStr( v, buf, BUF_SIZE );
2425     PushAttribute( name, buf );
2426 }
2427 
2428 
2429 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2430 {
2431     char buf[BUF_SIZE];
2432     XMLUtil::ToStr( v, buf, BUF_SIZE );
2433     PushAttribute( name, buf );
2434 }
2435 
2436 
2437 void XMLPrinter::PushAttribute(const char* name, int64_t v)
2438 {
2439     char buf[BUF_SIZE];
2440     XMLUtil::ToStr(v, buf, BUF_SIZE);
2441     PushAttribute(name, buf);
2442 }
2443 
2444 
2445 void XMLPrinter::PushAttribute( const char* name, bool v )
2446 {
2447     char buf[BUF_SIZE];
2448     XMLUtil::ToStr( v, buf, BUF_SIZE );
2449     PushAttribute( name, buf );
2450 }
2451 
2452 
2453 void XMLPrinter::PushAttribute( const char* name, double v )
2454 {
2455     char buf[BUF_SIZE];
2456     XMLUtil::ToStr( v, buf, BUF_SIZE );
2457     PushAttribute( name, buf );
2458 }
2459 
2460 
2461 void XMLPrinter::CloseElement( bool compactMode )
2462 {
2463     --_depth;
2464     const char* name = _stack.Pop();
2465 
2466     if ( _elementJustOpened ) {
2467         Print( "/>" );
2468     }
2469     else {
2470         if ( _textDepth < 0 && !compactMode) {
2471             Print( "\n" );
2472             PrintSpace( _depth );
2473         }
2474         Print( "</%s>", name );
2475     }
2476 
2477     if ( _textDepth == _depth ) {
2478         _textDepth = -1;
2479     }
2480     if ( _depth == 0 && !compactMode) {
2481         Print( "\n" );
2482     }
2483     _elementJustOpened = false;
2484 }
2485 
2486 
2487 void XMLPrinter::SealElementIfJustOpened()
2488 {
2489     if ( !_elementJustOpened ) {
2490         return;
2491     }
2492     _elementJustOpened = false;
2493     Print( ">" );
2494 }
2495 
2496 
2497 void XMLPrinter::PushText( const char* text, bool cdata )
2498 {
2499     _textDepth = _depth-1;
2500 
2501     SealElementIfJustOpened();
2502     if ( cdata ) {
2503         Print( "<![CDATA[%s]]>", text );
2504     }
2505     else {
2506         PrintString( text, true );
2507     }
2508 }
2509 
2510 void XMLPrinter::PushText( int64_t value )
2511 {
2512     char buf[BUF_SIZE];
2513     XMLUtil::ToStr( value, buf, BUF_SIZE );
2514     PushText( buf, false );
2515 }
2516 
2517 void XMLPrinter::PushText( int value )
2518 {
2519     char buf[BUF_SIZE];
2520     XMLUtil::ToStr( value, buf, BUF_SIZE );
2521     PushText( buf, false );
2522 }
2523 
2524 
2525 void XMLPrinter::PushText( unsigned value )
2526 {
2527     char buf[BUF_SIZE];
2528     XMLUtil::ToStr( value, buf, BUF_SIZE );
2529     PushText( buf, false );
2530 }
2531 
2532 
2533 void XMLPrinter::PushText( bool value )
2534 {
2535     char buf[BUF_SIZE];
2536     XMLUtil::ToStr( value, buf, BUF_SIZE );
2537     PushText( buf, false );
2538 }
2539 
2540 
2541 void XMLPrinter::PushText( float value )
2542 {
2543     char buf[BUF_SIZE];
2544     XMLUtil::ToStr( value, buf, BUF_SIZE );
2545     PushText( buf, false );
2546 }
2547 
2548 
2549 void XMLPrinter::PushText( double value )
2550 {
2551     char buf[BUF_SIZE];
2552     XMLUtil::ToStr( value, buf, BUF_SIZE );
2553     PushText( buf, false );
2554 }
2555 
2556 
2557 void XMLPrinter::PushComment( const char* comment )
2558 {
2559     SealElementIfJustOpened();
2560     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2561         Print( "\n" );
2562         PrintSpace( _depth );
2563     }
2564     _firstElement = false;
2565     Print( "<!--%s-->", comment );
2566 }
2567 
2568 
2569 void XMLPrinter::PushDeclaration( const char* value )
2570 {
2571     SealElementIfJustOpened();
2572     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2573         Print( "\n" );
2574         PrintSpace( _depth );
2575     }
2576     _firstElement = false;
2577     Print( "<?%s?>", value );
2578 }
2579 
2580 
2581 void XMLPrinter::PushUnknown( const char* value )
2582 {
2583     SealElementIfJustOpened();
2584     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2585         Print( "\n" );
2586         PrintSpace( _depth );
2587     }
2588     _firstElement = false;
2589     Print( "<!%s>", value );
2590 }
2591 
2592 
2593 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2594 {
2595     _processEntities = doc.ProcessEntities();
2596     if ( doc.HasBOM() ) {
2597         PushHeader( true, false );
2598     }
2599     return true;
2600 }
2601 
2602 
2603 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2604 {
2605     const XMLElement* parentElem = 0;
2606     if ( element.Parent() ) {
2607         parentElem = element.Parent()->ToElement();
2608     }
2609     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2610     OpenElement( element.Name(), compactMode );
2611     while ( attribute ) {
2612         PushAttribute( attribute->Name(), attribute->Value() );
2613         attribute = attribute->Next();
2614     }
2615     return true;
2616 }
2617 
2618 
2619 bool XMLPrinter::VisitExit( const XMLElement& element )
2620 {
2621     CloseElement( CompactMode(element) );
2622     return true;
2623 }
2624 
2625 
2626 bool XMLPrinter::Visit( const XMLText& text )
2627 {
2628     PushText( text.Value(), text.CData() );
2629     return true;
2630 }
2631 
2632 
2633 bool XMLPrinter::Visit( const XMLComment& comment )
2634 {
2635     PushComment( comment.Value() );
2636     return true;
2637 }
2638 
2639 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2640 {
2641     PushDeclaration( declaration.Value() );
2642     return true;
2643 }
2644 
2645 
2646 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2647 {
2648     PushUnknown( unknown.Value() );
2649     return true;
2650 }
2651 
2652 }   // namespace tinyxml2

2653