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 
     24 #include "tinyxml2.h"
     25 
     26 #include <new>		// yes, this one new style header, is in the Android SDK.
     27 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
     28 #   include <stddef.h>
     29 #   include <stdarg.h>
     30 #else
     31 #   include <cstddef>
     32 #   include <cstdarg>
     33 #endif
     34 
     35 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
     36 	// Microsoft Visual Studio, version 2005 and higher. Not WinCE.
     37 	/*int _snprintf_s(
     38 	   char *buffer,
     39 	   size_t sizeOfBuffer,
     40 	   size_t count,
     41 	   const char *format [,
     42 		  argument] ...
     43 	);*/
     44 	static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
     45 	{
     46 		va_list va;
     47 		va_start( va, format );
     48 		int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
     49 		va_end( va );
     50 		return result;
     51 	}
     52 
     53 	static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
     54 	{
     55 		int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
     56 		return result;
     57 	}
     58 
     59 	#define TIXML_VSCPRINTF	_vscprintf
     60 	#define TIXML_SSCANF	sscanf_s
     61 #elif defined _MSC_VER
     62 	// Microsoft Visual Studio 2003 and earlier or WinCE
     63 	#define TIXML_SNPRINTF	_snprintf
     64 	#define TIXML_VSNPRINTF _vsnprintf
     65 	#define TIXML_SSCANF	sscanf
     66 	#if (_MSC_VER < 1400 ) && (!defined WINCE)
     67 		// Microsoft Visual Studio 2003 and not WinCE.
     68 		#define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
     69 	#else
     70 		// Microsoft Visual Studio 2003 and earlier or WinCE.
     71 		static inline int TIXML_VSCPRINTF( const char* format, va_list va )
     72 		{
     73 			int len = 512;
     74 			for (;;) {
     75 				len = len*2;
     76 				char* str = new char[len]();
     77 				const int required = _vsnprintf(str, len, format, va);
     78 				delete[] str;
     79 				if ( required != -1 ) {
     80 					TIXMLASSERT( required >= 0 );
     81 					len = required;
     82 					break;
     83 				}
     84 			}
     85 			TIXMLASSERT( len >= 0 );
     86 			return len;
     87 		}
     88 	#endif
     89 #else
     90 	// GCC version 3 and higher
     91 	//#warning( "Using sn* functions." )
     92 	#define TIXML_SNPRINTF	snprintf
     93 	#define TIXML_VSNPRINTF	vsnprintf
     94 	static inline int TIXML_VSCPRINTF( const char* format, va_list va )
     95 	{
     96 		int len = vsnprintf( 0, 0, format, va );
     97 		TIXMLASSERT( len >= 0 );
     98 		return len;
     99 	}
    100 	#define TIXML_SSCANF   sscanf
    101 #endif
    102 
    103 
    104 static const char LINE_FEED				= (char)0x0a;			// all line endings are normalized to LF
    105 static const char LF = LINE_FEED;
    106 static const char CARRIAGE_RETURN		= (char)0x0d;			// CR gets filtered out
    107 static const char CR = CARRIAGE_RETURN;
    108 static const char SINGLE_QUOTE			= '\'';
    109 static const char DOUBLE_QUOTE			= '\"';
    110 
    111 // Bunch of unicode info at:
    112 //		http://www.unicode.org/faq/utf_bom.html
    113 //	ef bb bf (Microsoft "lead bytes") - designates UTF-8
    114 
    115 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
    116 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
    117 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
    118 
    119 namespace tinyxml2
    120 {
    121 
    122 struct Entity {
    123     const char* pattern;
    124     int length;
    125     char value;
    126 };
    127 
    128 static const int NUM_ENTITIES = 5;
    129 static const Entity entities[NUM_ENTITIES] = {
    130     { "quot", 4,	DOUBLE_QUOTE },
    131     { "amp", 3,		'&'  },
    132     { "apos", 4,	SINGLE_QUOTE },
    133     { "lt",	2, 		'<'	 },
    134     { "gt",	2,		'>'	 }
    135 };
    136 
    137 
    138 StrPair::~StrPair()
    139 {
    140     Reset();
    141 }
    142 
    143 
    144 void StrPair::TransferTo( StrPair* other )
    145 {
    146     if ( this == other ) {
    147         return;
    148     }
    149     // This in effect implements the assignment operator by "moving"
    150     // ownership (as in auto_ptr).
    151 
    152     TIXMLASSERT( other != 0 );
    153     TIXMLASSERT( other->_flags == 0 );
    154     TIXMLASSERT( other->_start == 0 );
    155     TIXMLASSERT( other->_end == 0 );
    156 
    157     other->Reset();
    158 
    159     other->_flags = _flags;
    160     other->_start = _start;
    161     other->_end = _end;
    162 
    163     _flags = 0;
    164     _start = 0;
    165     _end = 0;
    166 }
    167 
    168 
    169 void StrPair::Reset()
    170 {
    171     if ( _flags & NEEDS_DELETE ) {
    172         delete [] _start;
    173     }
    174     _flags = 0;
    175     _start = 0;
    176     _end = 0;
    177 }
    178 
    179 
    180 void StrPair::SetStr( const char* str, int flags )
    181 {
    182     TIXMLASSERT( str );
    183     Reset();
    184     size_t len = strlen( str );
    185     TIXMLASSERT( _start == 0 );
    186     _start = new char[ len+1 ];
    187     memcpy( _start, str, len+1 );
    188     _end = _start + len;
    189     _flags = flags | NEEDS_DELETE;
    190 }
    191 
    192 
    193 char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
    194 {
    195     TIXMLASSERT( p );
    196     TIXMLASSERT( endTag && *endTag );
    197 	TIXMLASSERT(curLineNumPtr);
    198 
    199     char* start = p;
    200     char  endChar = *endTag;
    201     size_t length = strlen( endTag );
    202 
    203     // Inner loop of text parsing.
    204     while ( *p ) {
    205         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
    206             Set( start, p, strFlags );
    207             return p + length;
    208         } else if (*p == '\n') {
    209             ++(*curLineNumPtr);
    210         }
    211         ++p;
    212         TIXMLASSERT( p );
    213     }
    214     return 0;
    215 }
    216 
    217 
    218 char* StrPair::ParseName( char* p )
    219 {
    220     if ( !p || !(*p) ) {
    221         return 0;
    222     }
    223     if ( !XMLUtil::IsNameStartChar( *p ) ) {
    224         return 0;
    225     }
    226 
    227     char* const start = p;
    228     ++p;
    229     while ( *p && XMLUtil::IsNameChar( *p ) ) {
    230         ++p;
    231     }
    232 
    233     Set( start, p, 0 );
    234     return p;
    235 }
    236 
    237 
    238 void StrPair::CollapseWhitespace()
    239 {
    240     // Adjusting _start would cause undefined behavior on delete[]
    241     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
    242     // Trim leading space.
    243     _start = XMLUtil::SkipWhiteSpace( _start, 0 );
    244 
    245     if ( *_start ) {
    246         const char* p = _start;	// the read pointer
    247         char* q = _start;	// the write pointer
    248 
    249         while( *p ) {
    250             if ( XMLUtil::IsWhiteSpace( *p )) {
    251                 p = XMLUtil::SkipWhiteSpace( p, 0 );
    252                 if ( *p == 0 ) {
    253                     break;    // don't write to q; this trims the trailing space.
    254                 }
    255                 *q = ' ';
    256                 ++q;
    257             }
    258             *q = *p;
    259             ++q;
    260             ++p;
    261         }
    262         *q = 0;
    263     }
    264 }
    265 
    266 
    267 const char* StrPair::GetStr()
    268 {
    269     TIXMLASSERT( _start );
    270     TIXMLASSERT( _end );
    271     if ( _flags & NEEDS_FLUSH ) {
    272         *_end = 0;
    273         _flags ^= NEEDS_FLUSH;
    274 
    275         if ( _flags ) {
    276             const char* p = _start;	// the read pointer
    277             char* q = _start;	// the write pointer
    278 
    279             while( p < _end ) {
    280                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
    281                     // CR-LF pair becomes LF
    282                     // CR alone becomes LF
    283                     // LF-CR becomes LF
    284                     if ( *(p+1) == LF ) {
    285                         p += 2;
    286                     }
    287                     else {
    288                         ++p;
    289                     }
    290                     *q = LF;
    291                     ++q;
    292                 }
    293                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
    294                     if ( *(p+1) == CR ) {
    295                         p += 2;
    296                     }
    297                     else {
    298                         ++p;
    299                     }
    300                     *q = LF;
    301                     ++q;
    302                 }
    303                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
    304                     // Entities handled by tinyXML2:
    305                     // - special entities in the entity table [in/out]
    306                     // - numeric character reference [in]
    307                     //   &#20013; or &#x4e2d;
    308 
    309                     if ( *(p+1) == '#' ) {
    310                         const int buflen = 10;
    311                         char buf[buflen] = { 0 };
    312                         int len = 0;
    313                         char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
    314                         if ( adjusted == 0 ) {
    315                             *q = *p;
    316                             ++p;
    317                             ++q;
    318                         }
    319                         else {
    320                             TIXMLASSERT( 0 <= len && len <= buflen );
    321                             TIXMLASSERT( q + len <= adjusted );
    322                             p = adjusted;
    323                             memcpy( q, buf, len );
    324                             q += len;
    325                         }
    326                     }
    327                     else {
    328                         bool entityFound = false;
    329                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
    330                             const Entity& entity = entities[i];
    331                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
    332                                     && *( p + entity.length + 1 ) == ';' ) {
    333                                 // Found an entity - convert.
    334                                 *q = entity.value;
    335                                 ++q;
    336                                 p += entity.length + 2;
    337                                 entityFound = true;
    338                                 break;
    339                             }
    340                         }
    341                         if ( !entityFound ) {
    342                             // fixme: treat as error?
    343                             ++p;
    344                             ++q;
    345                         }
    346                     }
    347                 }
    348                 else {
    349                     *q = *p;
    350                     ++p;
    351                     ++q;
    352                 }
    353             }
    354             *q = 0;
    355         }
    356         // The loop below has plenty going on, and this
    357         // is a less useful mode. Break it out.
    358         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
    359             CollapseWhitespace();
    360         }
    361         _flags = (_flags & NEEDS_DELETE);
    362     }
    363     TIXMLASSERT( _start );
    364     return _start;
    365 }
    366 
    367 
    368 
    369 
    370 // --------- XMLUtil ----------- //
    371 
    372 const char* XMLUtil::writeBoolTrue  = "true";
    373 const char* XMLUtil::writeBoolFalse = "false";
    374 
    375 void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
    376 {
    377 	static const char* defTrue  = "true";
    378 	static const char* defFalse = "false";
    379 
    380 	writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
    381 	writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
    382 }
    383 
    384 
    385 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
    386 {
    387     TIXMLASSERT( p );
    388     TIXMLASSERT( bom );
    389     *bom = false;
    390     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
    391     // Check for BOM:
    392     if (    *(pu+0) == TIXML_UTF_LEAD_0
    393             && *(pu+1) == TIXML_UTF_LEAD_1
    394             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
    395         *bom = true;
    396         p += 3;
    397     }
    398     TIXMLASSERT( p );
    399     return p;
    400 }
    401 
    402 
    403 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
    404 {
    405     const unsigned long BYTE_MASK = 0xBF;
    406     const unsigned long BYTE_MARK = 0x80;
    407     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
    408 
    409     if (input < 0x80) {
    410         *length = 1;
    411     }
    412     else if ( input < 0x800 ) {
    413         *length = 2;
    414     }
    415     else if ( input < 0x10000 ) {
    416         *length = 3;
    417     }
    418     else if ( input < 0x200000 ) {
    419         *length = 4;
    420     }
    421     else {
    422         *length = 0;    // This code won't convert this correctly anyway.
    423         return;
    424     }
    425 
    426     output += *length;
    427 
    428     // Scary scary fall throughs are annotated with carefully designed comments
    429     // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
    430     switch (*length) {
    431         case 4:
    432             --output;
    433             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    434             input >>= 6;
    435             //fall through
    436         case 3:
    437             --output;
    438             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    439             input >>= 6;
    440             //fall through
    441         case 2:
    442             --output;
    443             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
    444             input >>= 6;
    445             //fall through
    446         case 1:
    447             --output;
    448             *output = (char)(input | FIRST_BYTE_MARK[*length]);
    449             break;
    450         default:
    451             TIXMLASSERT( false );
    452     }
    453 }
    454 
    455 
    456 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
    457 {
    458     // Presume an entity, and pull it out.
    459     *length = 0;
    460 
    461     if ( *(p+1) == '#' && *(p+2) ) {
    462         unsigned long ucs = 0;
    463         TIXMLASSERT( sizeof( ucs ) >= 4 );
    464         ptrdiff_t delta = 0;
    465         unsigned mult = 1;
    466         static const char SEMICOLON = ';';
    467 
    468         if ( *(p+2) == 'x' ) {
    469             // Hexadecimal.
    470             const char* q = p+3;
    471             if ( !(*q) ) {
    472                 return 0;
    473             }
    474 
    475             q = strchr( q, SEMICOLON );
    476 
    477             if ( !q ) {
    478                 return 0;
    479             }
    480             TIXMLASSERT( *q == SEMICOLON );
    481 
    482             delta = q-p;
    483             --q;
    484 
    485             while ( *q != 'x' ) {
    486                 unsigned int digit = 0;
    487 
    488                 if ( *q >= '0' && *q <= '9' ) {
    489                     digit = *q - '0';
    490                 }
    491                 else if ( *q >= 'a' && *q <= 'f' ) {
    492                     digit = *q - 'a' + 10;
    493                 }
    494                 else if ( *q >= 'A' && *q <= 'F' ) {
    495                     digit = *q - 'A' + 10;
    496                 }
    497                 else {
    498                     return 0;
    499                 }
    500                 TIXMLASSERT( digit < 16 );
    501                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
    502                 const unsigned int digitScaled = mult * digit;
    503                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
    504                 ucs += digitScaled;
    505                 TIXMLASSERT( mult <= UINT_MAX / 16 );
    506                 mult *= 16;
    507                 --q;
    508             }
    509         }
    510         else {
    511             // Decimal.
    512             const char* q = p+2;
    513             if ( !(*q) ) {
    514                 return 0;
    515             }
    516 
    517             q = strchr( q, SEMICOLON );
    518 
    519             if ( !q ) {
    520                 return 0;
    521             }
    522             TIXMLASSERT( *q == SEMICOLON );
    523 
    524             delta = q-p;
    525             --q;
    526 
    527             while ( *q != '#' ) {
    528                 if ( *q >= '0' && *q <= '9' ) {
    529                     const unsigned int digit = *q - '0';
    530                     TIXMLASSERT( digit < 10 );
    531                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
    532                     const unsigned int digitScaled = mult * digit;
    533                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
    534                     ucs += digitScaled;
    535                 }
    536                 else {
    537                     return 0;
    538                 }
    539                 TIXMLASSERT( mult <= UINT_MAX / 10 );
    540                 mult *= 10;
    541                 --q;
    542             }
    543         }
    544         // convert the UCS to UTF-8
    545         ConvertUTF32ToUTF8( ucs, value, length );
    546         return p + delta + 1;
    547     }
    548     return p+1;
    549 }
    550 
    551 
    552 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
    553 {
    554     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
    555 }
    556 
    557 
    558 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
    559 {
    560     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
    561 }
    562 
    563 
    564 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
    565 {
    566     TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
    567 }
    568 
    569 /*
    570 	ToStr() of a number is a very tricky topic.
    571 	https://github.com/leethomason/tinyxml2/issues/106
    572 */
    573 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
    574 {
    575     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
    576 }
    577 
    578 
    579 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
    580 {
    581     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
    582 }
    583 
    584 
    585 void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
    586 {
    587 	// horrible syntax trick to make the compiler happy about %lld
    588 	TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
    589 }
    590 
    591 
    592 bool XMLUtil::ToInt( const char* str, int* value )
    593 {
    594     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
    595         return true;
    596     }
    597     return false;
    598 }
    599 
    600 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
    601 {
    602     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
    603         return true;
    604     }
    605     return false;
    606 }
    607 
    608 bool XMLUtil::ToBool( const char* str, bool* value )
    609 {
    610     int ival = 0;
    611     if ( ToInt( str, &ival )) {
    612         *value = (ival==0) ? false : true;
    613         return true;
    614     }
    615     if ( StringEqual( str, "true" ) ) {
    616         *value = true;
    617         return true;
    618     }
    619     else if ( StringEqual( str, "false" ) ) {
    620         *value = false;
    621         return true;
    622     }
    623     return false;
    624 }
    625 
    626 
    627 bool XMLUtil::ToFloat( const char* str, float* value )
    628 {
    629     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
    630         return true;
    631     }
    632     return false;
    633 }
    634 
    635 
    636 bool XMLUtil::ToDouble( const char* str, double* value )
    637 {
    638     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
    639         return true;
    640     }
    641     return false;
    642 }
    643 
    644 
    645 bool XMLUtil::ToInt64(const char* str, int64_t* value)
    646 {
    647 	long long v = 0;	// horrible syntax trick to make the compiler happy about %lld
    648 	if (TIXML_SSCANF(str, "%lld", &v) == 1) {
    649 		*value = (int64_t)v;
    650 		return true;
    651 	}
    652 	return false;
    653 }
    654 
    655 
    656 char* XMLDocument::Identify( char* p, XMLNode** node )
    657 {
    658     TIXMLASSERT( node );
    659     TIXMLASSERT( p );
    660     char* const start = p;
    661     int const startLine = _parseCurLineNum;
    662     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
    663     if( !*p ) {
    664         *node = 0;
    665         TIXMLASSERT( p );
    666         return p;
    667     }
    668 
    669     // These strings define the matching patterns:
    670     static const char* xmlHeader		= { "<?" };
    671     static const char* commentHeader	= { "<!--" };
    672     static const char* cdataHeader		= { "<![CDATA[" };
    673     static const char* dtdHeader		= { "<!" };
    674     static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
    675 
    676     static const int xmlHeaderLen		= 2;
    677     static const int commentHeaderLen	= 4;
    678     static const int cdataHeaderLen		= 9;
    679     static const int dtdHeaderLen		= 2;
    680     static const int elementHeaderLen	= 1;
    681 
    682     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
    683     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
    684     XMLNode* returnNode = 0;
    685     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
    686         returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
    687         returnNode->_parseLineNum = _parseCurLineNum;
    688         p += xmlHeaderLen;
    689     }
    690     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
    691         returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
    692         returnNode->_parseLineNum = _parseCurLineNum;
    693         p += commentHeaderLen;
    694     }
    695     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
    696         XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
    697         returnNode = text;
    698         returnNode->_parseLineNum = _parseCurLineNum;
    699         p += cdataHeaderLen;
    700         text->SetCData( true );
    701     }
    702     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
    703         returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
    704         returnNode->_parseLineNum = _parseCurLineNum;
    705         p += dtdHeaderLen;
    706     }
    707     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
    708         returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );
    709         returnNode->_parseLineNum = _parseCurLineNum;
    710         p += elementHeaderLen;
    711     }
    712     else {
    713         returnNode = CreateUnlinkedNode<XMLText>( _textPool );
    714         returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
    715         p = start;	// Back it up, all the text counts.
    716         _parseCurLineNum = startLine;
    717     }
    718 
    719     TIXMLASSERT( returnNode );
    720     TIXMLASSERT( p );
    721     *node = returnNode;
    722     return p;
    723 }
    724 
    725 
    726 bool XMLDocument::Accept( XMLVisitor* visitor ) const
    727 {
    728     TIXMLASSERT( visitor );
    729     if ( visitor->VisitEnter( *this ) ) {
    730         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
    731             if ( !node->Accept( visitor ) ) {
    732                 break;
    733             }
    734         }
    735     }
    736     return visitor->VisitExit( *this );
    737 }
    738 
    739 
    740 // --------- XMLNode ----------- //
    741 
    742 XMLNode::XMLNode( XMLDocument* doc ) :
    743     _document( doc ),
    744     _parent( 0 ),
    745     _value(),
    746     _parseLineNum( 0 ),
    747     _firstChild( 0 ), _lastChild( 0 ),
    748     _prev( 0 ), _next( 0 ),
    749 	_userData( 0 ),
    750     _memPool( 0 )
    751 {
    752 }
    753 
    754 
    755 XMLNode::~XMLNode()
    756 {
    757     DeleteChildren();
    758     if ( _parent ) {
    759         _parent->Unlink( this );
    760     }
    761 }
    762 
    763 const char* XMLNode::Value() const
    764 {
    765     // Edge case: XMLDocuments don't have a Value. Return null.
    766     if ( this->ToDocument() )
    767         return 0;
    768     return _value.GetStr();
    769 }
    770 
    771 void XMLNode::SetValue( const char* str, bool staticMem )
    772 {
    773     if ( staticMem ) {
    774         _value.SetInternedStr( str );
    775     }
    776     else {
    777         _value.SetStr( str );
    778     }
    779 }
    780 
    781 XMLNode* XMLNode::DeepClone(XMLDocument* target) const
    782 {
    783 	XMLNode* clone = this->ShallowClone(target);
    784 	if (!clone) return 0;
    785 
    786 	for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
    787 		XMLNode* childClone = child->DeepClone(target);
    788 		TIXMLASSERT(childClone);
    789 		clone->InsertEndChild(childClone);
    790 	}
    791 	return clone;
    792 }
    793 
    794 void XMLNode::DeleteChildren()
    795 {
    796     while( _firstChild ) {
    797         TIXMLASSERT( _lastChild );
    798         DeleteChild( _firstChild );
    799     }
    800     _firstChild = _lastChild = 0;
    801 }
    802 
    803 
    804 void XMLNode::Unlink( XMLNode* child )
    805 {
    806     TIXMLASSERT( child );
    807     TIXMLASSERT( child->_document == _document );
    808     TIXMLASSERT( child->_parent == this );
    809     if ( child == _firstChild ) {
    810         _firstChild = _firstChild->_next;
    811     }
    812     if ( child == _lastChild ) {
    813         _lastChild = _lastChild->_prev;
    814     }
    815 
    816     if ( child->_prev ) {
    817         child->_prev->_next = child->_next;
    818     }
    819     if ( child->_next ) {
    820         child->_next->_prev = child->_prev;
    821     }
    822 	child->_next = 0;
    823 	child->_prev = 0;
    824 	child->_parent = 0;
    825 }
    826 
    827 
    828 void XMLNode::DeleteChild( XMLNode* node )
    829 {
    830     TIXMLASSERT( node );
    831     TIXMLASSERT( node->_document == _document );
    832     TIXMLASSERT( node->_parent == this );
    833     Unlink( node );
    834 	TIXMLASSERT(node->_prev == 0);
    835 	TIXMLASSERT(node->_next == 0);
    836 	TIXMLASSERT(node->_parent == 0);
    837     DeleteNode( node );
    838 }
    839 
    840 
    841 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
    842 {
    843     TIXMLASSERT( addThis );
    844     if ( addThis->_document != _document ) {
    845         TIXMLASSERT( false );
    846         return 0;
    847     }
    848     InsertChildPreamble( addThis );
    849 
    850     if ( _lastChild ) {
    851         TIXMLASSERT( _firstChild );
    852         TIXMLASSERT( _lastChild->_next == 0 );
    853         _lastChild->_next = addThis;
    854         addThis->_prev = _lastChild;
    855         _lastChild = addThis;
    856 
    857         addThis->_next = 0;
    858     }
    859     else {
    860         TIXMLASSERT( _firstChild == 0 );
    861         _firstChild = _lastChild = addThis;
    862 
    863         addThis->_prev = 0;
    864         addThis->_next = 0;
    865     }
    866     addThis->_parent = this;
    867     return addThis;
    868 }
    869 
    870 
    871 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
    872 {
    873     TIXMLASSERT( addThis );
    874     if ( addThis->_document != _document ) {
    875         TIXMLASSERT( false );
    876         return 0;
    877     }
    878     InsertChildPreamble( addThis );
    879 
    880     if ( _firstChild ) {
    881         TIXMLASSERT( _lastChild );
    882         TIXMLASSERT( _firstChild->_prev == 0 );
    883 
    884         _firstChild->_prev = addThis;
    885         addThis->_next = _firstChild;
    886         _firstChild = addThis;
    887 
    888         addThis->_prev = 0;
    889     }
    890     else {
    891         TIXMLASSERT( _lastChild == 0 );
    892         _firstChild = _lastChild = addThis;
    893 
    894         addThis->_prev = 0;
    895         addThis->_next = 0;
    896     }
    897     addThis->_parent = this;
    898     return addThis;
    899 }
    900 
    901 
    902 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
    903 {
    904     TIXMLASSERT( addThis );
    905     if ( addThis->_document != _document ) {
    906         TIXMLASSERT( false );
    907         return 0;
    908     }
    909 
    910     TIXMLASSERT( afterThis );
    911 
    912     if ( afterThis->_parent != this ) {
    913         TIXMLASSERT( false );
    914         return 0;
    915     }
    916     if ( afterThis == addThis ) {
    917         // Current state: BeforeThis -> AddThis -> OneAfterAddThis
    918         // Now AddThis must disappear from it's location and then
    919         // reappear between BeforeThis and OneAfterAddThis.
    920         // So just leave it where it is.
    921         return addThis;
    922     }
    923 
    924     if ( afterThis->_next == 0 ) {
    925         // The last node or the only node.
    926         return InsertEndChild( addThis );
    927     }
    928     InsertChildPreamble( addThis );
    929     addThis->_prev = afterThis;
    930     addThis->_next = afterThis->_next;
    931     afterThis->_next->_prev = addThis;
    932     afterThis->_next = addThis;
    933     addThis->_parent = this;
    934     return addThis;
    935 }
    936 
    937 
    938 
    939 
    940 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
    941 {
    942     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
    943         const XMLElement* element = node->ToElementWithName( name );
    944         if ( element ) {
    945             return element;
    946         }
    947     }
    948     return 0;
    949 }
    950 
    951 
    952 const XMLElement* XMLNode::LastChildElement( const char* name ) const
    953 {
    954     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
    955         const XMLElement* element = node->ToElementWithName( name );
    956         if ( element ) {
    957             return element;
    958         }
    959     }
    960     return 0;
    961 }
    962 
    963 
    964 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
    965 {
    966     for( const XMLNode* node = _next; node; node = node->_next ) {
    967         const XMLElement* element = node->ToElementWithName( name );
    968         if ( element ) {
    969             return element;
    970         }
    971     }
    972     return 0;
    973 }
    974 
    975 
    976 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
    977 {
    978     for( const XMLNode* node = _prev; node; node = node->_prev ) {
    979         const XMLElement* element = node->ToElementWithName( name );
    980         if ( element ) {
    981             return element;
    982         }
    983     }
    984     return 0;
    985 }
    986 
    987 
    988 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
    989 {
    990     // This is a recursive method, but thinking about it "at the current level"
    991     // it is a pretty simple flat list:
    992     //		<foo/>
    993     //		<!-- comment -->
    994     //
    995     // With a special case:
    996     //		<foo>
    997     //		</foo>
    998     //		<!-- comment -->
    999     //
   1000     // Where the closing element (/foo) *must* be the next thing after the opening
   1001     // element, and the names must match. BUT the tricky bit is that the closing
   1002     // element will be read by the child.
   1003     //
   1004     // 'endTag' is the end tag for this node, it is returned by a call to a child.
   1005     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
   1006 
   1007 	XMLDocument::DepthTracker tracker(_document);
   1008 	if (_document->Error())
   1009 		return 0;
   1010 
   1011 	while( p && *p ) {
   1012         XMLNode* node = 0;
   1013 
   1014         p = _document->Identify( p, &node );
   1015         TIXMLASSERT( p );
   1016         if ( node == 0 ) {
   1017             break;
   1018         }
   1019 
   1020         int initialLineNum = node->_parseLineNum;
   1021 
   1022         StrPair endTag;
   1023         p = node->ParseDeep( p, &endTag, curLineNumPtr );
   1024         if ( !p ) {
   1025             DeleteNode( node );
   1026             if ( !_document->Error() ) {
   1027                 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
   1028             }
   1029             break;
   1030         }
   1031 
   1032         XMLDeclaration* decl = node->ToDeclaration();
   1033         if ( decl ) {
   1034             // Declarations are only allowed at document level
   1035             //
   1036             // Multiple declarations are allowed but all declarations
   1037             // must occur before anything else.
   1038             //
   1039             // Optimized due to a security test case. If the first node is
   1040             // a declaration, and the last node is a declaration, then only
   1041             // declarations have so far been addded.
   1042             bool wellLocated = false;
   1043 
   1044             if (ToDocument()) {
   1045                 if (FirstChild()) {
   1046                     wellLocated =
   1047                         FirstChild() &&
   1048                         FirstChild()->ToDeclaration() &&
   1049                         LastChild() &&
   1050                         LastChild()->ToDeclaration();
   1051                 }
   1052                 else {
   1053                     wellLocated = true;
   1054                 }
   1055             }
   1056             if ( !wellLocated ) {
   1057                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
   1058                 DeleteNode( node );
   1059                 break;
   1060             }
   1061         }
   1062 
   1063         XMLElement* ele = node->ToElement();
   1064         if ( ele ) {
   1065             // We read the end tag. Return it to the parent.
   1066             if ( ele->ClosingType() == XMLElement::CLOSING ) {
   1067                 if ( parentEndTag ) {
   1068                     ele->_value.TransferTo( parentEndTag );
   1069                 }
   1070                 node->_memPool->SetTracked();   // created and then immediately deleted.
   1071                 DeleteNode( node );
   1072                 return p;
   1073             }
   1074 
   1075             // Handle an end tag returned to this level.
   1076             // And handle a bunch of annoying errors.
   1077             bool mismatch = false;
   1078             if ( endTag.Empty() ) {
   1079                 if ( ele->ClosingType() == XMLElement::OPEN ) {
   1080                     mismatch = true;
   1081                 }
   1082             }
   1083             else {
   1084                 if ( ele->ClosingType() != XMLElement::OPEN ) {
   1085                     mismatch = true;
   1086                 }
   1087                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
   1088                     mismatch = true;
   1089                 }
   1090             }
   1091             if ( mismatch ) {
   1092                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
   1093                 DeleteNode( node );
   1094                 break;
   1095             }
   1096         }
   1097         InsertEndChild( node );
   1098     }
   1099     return 0;
   1100 }
   1101 
   1102 /*static*/ void XMLNode::DeleteNode( XMLNode* node )
   1103 {
   1104     if ( node == 0 ) {
   1105         return;
   1106     }
   1107 	TIXMLASSERT(node->_document);
   1108 	if (!node->ToDocument()) {
   1109 		node->_document->MarkInUse(node);
   1110 	}
   1111 
   1112     MemPool* pool = node->_memPool;
   1113     node->~XMLNode();
   1114     pool->Free( node );
   1115 }
   1116 
   1117 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
   1118 {
   1119     TIXMLASSERT( insertThis );
   1120     TIXMLASSERT( insertThis->_document == _document );
   1121 
   1122 	if (insertThis->_parent) {
   1123         insertThis->_parent->Unlink( insertThis );
   1124 	}
   1125 	else {
   1126 		insertThis->_document->MarkInUse(insertThis);
   1127         insertThis->_memPool->SetTracked();
   1128 	}
   1129 }
   1130 
   1131 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
   1132 {
   1133     const XMLElement* element = this->ToElement();
   1134     if ( element == 0 ) {
   1135         return 0;
   1136     }
   1137     if ( name == 0 ) {
   1138         return element;
   1139     }
   1140     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
   1141        return element;
   1142     }
   1143     return 0;
   1144 }
   1145 
   1146 // --------- XMLText ---------- //
   1147 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
   1148 {
   1149     if ( this->CData() ) {
   1150         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
   1151         if ( !p ) {
   1152             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
   1153         }
   1154         return p;
   1155     }
   1156     else {
   1157         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
   1158         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
   1159             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
   1160         }
   1161 
   1162         p = _value.ParseText( p, "<", flags, curLineNumPtr );
   1163         if ( p && *p ) {
   1164             return p-1;
   1165         }
   1166         if ( !p ) {
   1167             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
   1168         }
   1169     }
   1170     return 0;
   1171 }
   1172 
   1173 
   1174 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
   1175 {
   1176     if ( !doc ) {
   1177         doc = _document;
   1178     }
   1179     XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
   1180     text->SetCData( this->CData() );
   1181     return text;
   1182 }
   1183 
   1184 
   1185 bool XMLText::ShallowEqual( const XMLNode* compare ) const
   1186 {
   1187     TIXMLASSERT( compare );
   1188     const XMLText* text = compare->ToText();
   1189     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
   1190 }
   1191 
   1192 
   1193 bool XMLText::Accept( XMLVisitor* visitor ) const
   1194 {
   1195     TIXMLASSERT( visitor );
   1196     return visitor->Visit( *this );
   1197 }
   1198 
   1199 
   1200 // --------- XMLComment ---------- //
   1201 
   1202 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
   1203 {
   1204 }
   1205 
   1206 
   1207 XMLComment::~XMLComment()
   1208 {
   1209 }
   1210 
   1211 
   1212 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
   1213 {
   1214     // Comment parses as text.
   1215     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
   1216     if ( p == 0 ) {
   1217         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
   1218     }
   1219     return p;
   1220 }
   1221 
   1222 
   1223 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
   1224 {
   1225     if ( !doc ) {
   1226         doc = _document;
   1227     }
   1228     XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
   1229     return comment;
   1230 }
   1231 
   1232 
   1233 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
   1234 {
   1235     TIXMLASSERT( compare );
   1236     const XMLComment* comment = compare->ToComment();
   1237     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
   1238 }
   1239 
   1240 
   1241 bool XMLComment::Accept( XMLVisitor* visitor ) const
   1242 {
   1243     TIXMLASSERT( visitor );
   1244     return visitor->Visit( *this );
   1245 }
   1246 
   1247 
   1248 // --------- XMLDeclaration ---------- //
   1249 
   1250 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
   1251 {
   1252 }
   1253 
   1254 
   1255 XMLDeclaration::~XMLDeclaration()
   1256 {
   1257     //printf( "~XMLDeclaration\n" );
   1258 }
   1259 
   1260 
   1261 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
   1262 {
   1263     // Declaration parses as text.
   1264     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
   1265     if ( p == 0 ) {
   1266         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
   1267     }
   1268     return p;
   1269 }
   1270 
   1271 
   1272 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
   1273 {
   1274     if ( !doc ) {
   1275         doc = _document;
   1276     }
   1277     XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
   1278     return dec;
   1279 }
   1280 
   1281 
   1282 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
   1283 {
   1284     TIXMLASSERT( compare );
   1285     const XMLDeclaration* declaration = compare->ToDeclaration();
   1286     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
   1287 }
   1288 
   1289 
   1290 
   1291 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
   1292 {
   1293     TIXMLASSERT( visitor );
   1294     return visitor->Visit( *this );
   1295 }
   1296 
   1297 // --------- XMLUnknown ---------- //
   1298 
   1299 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
   1300 {
   1301 }
   1302 
   1303 
   1304 XMLUnknown::~XMLUnknown()
   1305 {
   1306 }
   1307 
   1308 
   1309 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
   1310 {
   1311     // Unknown parses as text.
   1312     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
   1313     if ( !p ) {
   1314         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
   1315     }
   1316     return p;
   1317 }
   1318 
   1319 
   1320 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
   1321 {
   1322     if ( !doc ) {
   1323         doc = _document;
   1324     }
   1325     XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
   1326     return text;
   1327 }
   1328 
   1329 
   1330 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
   1331 {
   1332     TIXMLASSERT( compare );
   1333     const XMLUnknown* unknown = compare->ToUnknown();
   1334     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
   1335 }
   1336 
   1337 
   1338 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
   1339 {
   1340     TIXMLASSERT( visitor );
   1341     return visitor->Visit( *this );
   1342 }
   1343 
   1344 // --------- XMLAttribute ---------- //
   1345 
   1346 const char* XMLAttribute::Name() const
   1347 {
   1348     return _name.GetStr();
   1349 }
   1350 
   1351 const char* XMLAttribute::Value() const
   1352 {
   1353     return _value.GetStr();
   1354 }
   1355 
   1356 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
   1357 {
   1358     // Parse using the name rules: bug fix, was using ParseText before
   1359     p = _name.ParseName( p );
   1360     if ( !p || !*p ) {
   1361         return 0;
   1362     }
   1363 
   1364     // Skip white space before =
   1365     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
   1366     if ( *p != '=' ) {
   1367         return 0;
   1368     }
   1369 
   1370     ++p;	// move up to opening quote
   1371     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
   1372     if ( *p != '\"' && *p != '\'' ) {
   1373         return 0;
   1374     }
   1375 
   1376     char endTag[2] = { *p, 0 };
   1377     ++p;	// move past opening quote
   1378 
   1379     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
   1380     return p;
   1381 }
   1382 
   1383 
   1384 void XMLAttribute::SetName( const char* n )
   1385 {
   1386     _name.SetStr( n );
   1387 }
   1388 
   1389 
   1390 XMLError XMLAttribute::QueryIntValue( int* value ) const
   1391 {
   1392     if ( XMLUtil::ToInt( Value(), value )) {
   1393         return XML_SUCCESS;
   1394     }
   1395     return XML_WRONG_ATTRIBUTE_TYPE;
   1396 }
   1397 
   1398 
   1399 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
   1400 {
   1401     if ( XMLUtil::ToUnsigned( Value(), value )) {
   1402         return XML_SUCCESS;
   1403     }
   1404     return XML_WRONG_ATTRIBUTE_TYPE;
   1405 }
   1406 
   1407 
   1408 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
   1409 {
   1410 	if (XMLUtil::ToInt64(Value(), value)) {
   1411 		return XML_SUCCESS;
   1412 	}
   1413 	return XML_WRONG_ATTRIBUTE_TYPE;
   1414 }
   1415 
   1416 
   1417 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
   1418 {
   1419     if ( XMLUtil::ToBool( Value(), value )) {
   1420         return XML_SUCCESS;
   1421     }
   1422     return XML_WRONG_ATTRIBUTE_TYPE;
   1423 }
   1424 
   1425 
   1426 XMLError XMLAttribute::QueryFloatValue( float* value ) const
   1427 {
   1428     if ( XMLUtil::ToFloat( Value(), value )) {
   1429         return XML_SUCCESS;
   1430     }
   1431     return XML_WRONG_ATTRIBUTE_TYPE;
   1432 }
   1433 
   1434 
   1435 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
   1436 {
   1437     if ( XMLUtil::ToDouble( Value(), value )) {
   1438         return XML_SUCCESS;
   1439     }
   1440     return XML_WRONG_ATTRIBUTE_TYPE;
   1441 }
   1442 
   1443 
   1444 void XMLAttribute::SetAttribute( const char* v )
   1445 {
   1446     _value.SetStr( v );
   1447 }
   1448 
   1449 
   1450 void XMLAttribute::SetAttribute( int v )
   1451 {
   1452     char buf[BUF_SIZE];
   1453     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1454     _value.SetStr( buf );
   1455 }
   1456 
   1457 
   1458 void XMLAttribute::SetAttribute( unsigned v )
   1459 {
   1460     char buf[BUF_SIZE];
   1461     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1462     _value.SetStr( buf );
   1463 }
   1464 
   1465 
   1466 void XMLAttribute::SetAttribute(int64_t v)
   1467 {
   1468 	char buf[BUF_SIZE];
   1469 	XMLUtil::ToStr(v, buf, BUF_SIZE);
   1470 	_value.SetStr(buf);
   1471 }
   1472 
   1473 
   1474 
   1475 void XMLAttribute::SetAttribute( bool v )
   1476 {
   1477     char buf[BUF_SIZE];
   1478     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1479     _value.SetStr( buf );
   1480 }
   1481 
   1482 void XMLAttribute::SetAttribute( double v )
   1483 {
   1484     char buf[BUF_SIZE];
   1485     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1486     _value.SetStr( buf );
   1487 }
   1488 
   1489 void XMLAttribute::SetAttribute( float v )
   1490 {
   1491     char buf[BUF_SIZE];
   1492     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1493     _value.SetStr( buf );
   1494 }
   1495 
   1496 
   1497 // --------- XMLElement ---------- //
   1498 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
   1499     _closingType( OPEN ),
   1500     _rootAttribute( 0 )
   1501 {
   1502 }
   1503 
   1504 
   1505 XMLElement::~XMLElement()
   1506 {
   1507     while( _rootAttribute ) {
   1508         XMLAttribute* next = _rootAttribute->_next;
   1509         DeleteAttribute( _rootAttribute );
   1510         _rootAttribute = next;
   1511     }
   1512 }
   1513 
   1514 
   1515 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
   1516 {
   1517     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
   1518         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
   1519             return a;
   1520         }
   1521     }
   1522     return 0;
   1523 }
   1524 
   1525 
   1526 const char* XMLElement::Attribute( const char* name, const char* value ) const
   1527 {
   1528     const XMLAttribute* a = FindAttribute( name );
   1529     if ( !a ) {
   1530         return 0;
   1531     }
   1532     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
   1533         return a->Value();
   1534     }
   1535     return 0;
   1536 }
   1537 
   1538 int XMLElement::IntAttribute(const char* name, int defaultValue) const
   1539 {
   1540 	int i = defaultValue;
   1541 	QueryIntAttribute(name, &i);
   1542 	return i;
   1543 }
   1544 
   1545 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
   1546 {
   1547 	unsigned i = defaultValue;
   1548 	QueryUnsignedAttribute(name, &i);
   1549 	return i;
   1550 }
   1551 
   1552 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
   1553 {
   1554 	int64_t i = defaultValue;
   1555 	QueryInt64Attribute(name, &i);
   1556 	return i;
   1557 }
   1558 
   1559 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
   1560 {
   1561 	bool b = defaultValue;
   1562 	QueryBoolAttribute(name, &b);
   1563 	return b;
   1564 }
   1565 
   1566 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
   1567 {
   1568 	double d = defaultValue;
   1569 	QueryDoubleAttribute(name, &d);
   1570 	return d;
   1571 }
   1572 
   1573 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
   1574 {
   1575 	float f = defaultValue;
   1576 	QueryFloatAttribute(name, &f);
   1577 	return f;
   1578 }
   1579 
   1580 const char* XMLElement::GetText() const
   1581 {
   1582     if ( FirstChild() && FirstChild()->ToText() ) {
   1583         return FirstChild()->Value();
   1584     }
   1585     return 0;
   1586 }
   1587 
   1588 
   1589 void	XMLElement::SetText( const char* inText )
   1590 {
   1591 	if ( FirstChild() && FirstChild()->ToText() )
   1592 		FirstChild()->SetValue( inText );
   1593 	else {
   1594 		XMLText*	theText = GetDocument()->NewText( inText );
   1595 		InsertFirstChild( theText );
   1596 	}
   1597 }
   1598 
   1599 
   1600 void XMLElement::SetText( int v )
   1601 {
   1602     char buf[BUF_SIZE];
   1603     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1604     SetText( buf );
   1605 }
   1606 
   1607 
   1608 void XMLElement::SetText( unsigned v )
   1609 {
   1610     char buf[BUF_SIZE];
   1611     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1612     SetText( buf );
   1613 }
   1614 
   1615 
   1616 void XMLElement::SetText(int64_t v)
   1617 {
   1618 	char buf[BUF_SIZE];
   1619 	XMLUtil::ToStr(v, buf, BUF_SIZE);
   1620 	SetText(buf);
   1621 }
   1622 
   1623 
   1624 void XMLElement::SetText( bool v )
   1625 {
   1626     char buf[BUF_SIZE];
   1627     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1628     SetText( buf );
   1629 }
   1630 
   1631 
   1632 void XMLElement::SetText( float v )
   1633 {
   1634     char buf[BUF_SIZE];
   1635     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1636     SetText( buf );
   1637 }
   1638 
   1639 
   1640 void XMLElement::SetText( double v )
   1641 {
   1642     char buf[BUF_SIZE];
   1643     XMLUtil::ToStr( v, buf, BUF_SIZE );
   1644     SetText( buf );
   1645 }
   1646 
   1647 
   1648 XMLError XMLElement::QueryIntText( int* ival ) const
   1649 {
   1650     if ( FirstChild() && FirstChild()->ToText() ) {
   1651         const char* t = FirstChild()->Value();
   1652         if ( XMLUtil::ToInt( t, ival ) ) {
   1653             return XML_SUCCESS;
   1654         }
   1655         return XML_CAN_NOT_CONVERT_TEXT;
   1656     }
   1657     return XML_NO_TEXT_NODE;
   1658 }
   1659 
   1660 
   1661 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
   1662 {
   1663     if ( FirstChild() && FirstChild()->ToText() ) {
   1664         const char* t = FirstChild()->Value();
   1665         if ( XMLUtil::ToUnsigned( t, uval ) ) {
   1666             return XML_SUCCESS;
   1667         }
   1668         return XML_CAN_NOT_CONVERT_TEXT;
   1669     }
   1670     return XML_NO_TEXT_NODE;
   1671 }
   1672 
   1673 
   1674 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
   1675 {
   1676 	if (FirstChild() && FirstChild()->ToText()) {
   1677 		const char* t = FirstChild()->Value();
   1678 		if (XMLUtil::ToInt64(t, ival)) {
   1679 			return XML_SUCCESS;
   1680 		}
   1681 		return XML_CAN_NOT_CONVERT_TEXT;
   1682 	}
   1683 	return XML_NO_TEXT_NODE;
   1684 }
   1685 
   1686 
   1687 XMLError XMLElement::QueryBoolText( bool* bval ) const
   1688 {
   1689     if ( FirstChild() && FirstChild()->ToText() ) {
   1690         const char* t = FirstChild()->Value();
   1691         if ( XMLUtil::ToBool( t, bval ) ) {
   1692             return XML_SUCCESS;
   1693         }
   1694         return XML_CAN_NOT_CONVERT_TEXT;
   1695     }
   1696     return XML_NO_TEXT_NODE;
   1697 }
   1698 
   1699 
   1700 XMLError XMLElement::QueryDoubleText( double* dval ) const
   1701 {
   1702     if ( FirstChild() && FirstChild()->ToText() ) {
   1703         const char* t = FirstChild()->Value();
   1704         if ( XMLUtil::ToDouble( t, dval ) ) {
   1705             return XML_SUCCESS;
   1706         }
   1707         return XML_CAN_NOT_CONVERT_TEXT;
   1708     }
   1709     return XML_NO_TEXT_NODE;
   1710 }
   1711 
   1712 
   1713 XMLError XMLElement::QueryFloatText( float* fval ) const
   1714 {
   1715     if ( FirstChild() && FirstChild()->ToText() ) {
   1716         const char* t = FirstChild()->Value();
   1717         if ( XMLUtil::ToFloat( t, fval ) ) {
   1718             return XML_SUCCESS;
   1719         }
   1720         return XML_CAN_NOT_CONVERT_TEXT;
   1721     }
   1722     return XML_NO_TEXT_NODE;
   1723 }
   1724 
   1725 int XMLElement::IntText(int defaultValue) const
   1726 {
   1727 	int i = defaultValue;
   1728 	QueryIntText(&i);
   1729 	return i;
   1730 }
   1731 
   1732 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
   1733 {
   1734 	unsigned i = defaultValue;
   1735 	QueryUnsignedText(&i);
   1736 	return i;
   1737 }
   1738 
   1739 int64_t XMLElement::Int64Text(int64_t defaultValue) const
   1740 {
   1741 	int64_t i = defaultValue;
   1742 	QueryInt64Text(&i);
   1743 	return i;
   1744 }
   1745 
   1746 bool XMLElement::BoolText(bool defaultValue) const
   1747 {
   1748 	bool b = defaultValue;
   1749 	QueryBoolText(&b);
   1750 	return b;
   1751 }
   1752 
   1753 double XMLElement::DoubleText(double defaultValue) const
   1754 {
   1755 	double d = defaultValue;
   1756 	QueryDoubleText(&d);
   1757 	return d;
   1758 }
   1759 
   1760 float XMLElement::FloatText(float defaultValue) const
   1761 {
   1762 	float f = defaultValue;
   1763 	QueryFloatText(&f);
   1764 	return f;
   1765 }
   1766 
   1767 
   1768 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
   1769 {
   1770     XMLAttribute* last = 0;
   1771     XMLAttribute* attrib = 0;
   1772     for( attrib = _rootAttribute;
   1773             attrib;
   1774             last = attrib, attrib = attrib->_next ) {
   1775         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
   1776             break;
   1777         }
   1778     }
   1779     if ( !attrib ) {
   1780         attrib = CreateAttribute();
   1781         TIXMLASSERT( attrib );
   1782         if ( last ) {
   1783             TIXMLASSERT( last->_next == 0 );
   1784             last->_next = attrib;
   1785         }
   1786         else {
   1787             TIXMLASSERT( _rootAttribute == 0 );
   1788             _rootAttribute = attrib;
   1789         }
   1790         attrib->SetName( name );
   1791     }
   1792     return attrib;
   1793 }
   1794 
   1795 
   1796 void XMLElement::DeleteAttribute( const char* name )
   1797 {
   1798     XMLAttribute* prev = 0;
   1799     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
   1800         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
   1801             if ( prev ) {
   1802                 prev->_next = a->_next;
   1803             }
   1804             else {
   1805                 _rootAttribute = a->_next;
   1806             }
   1807             DeleteAttribute( a );
   1808             break;
   1809         }
   1810         prev = a;
   1811     }
   1812 }
   1813 
   1814 
   1815 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
   1816 {
   1817     XMLAttribute* prevAttribute = 0;
   1818 
   1819     // Read the attributes.
   1820     while( p ) {
   1821         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
   1822         if ( !(*p) ) {
   1823             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
   1824             return 0;
   1825         }
   1826 
   1827         // attribute.
   1828         if (XMLUtil::IsNameStartChar( *p ) ) {
   1829             XMLAttribute* attrib = CreateAttribute();
   1830             TIXMLASSERT( attrib );
   1831             attrib->_parseLineNum = _document->_parseCurLineNum;
   1832 
   1833             int attrLineNum = attrib->_parseLineNum;
   1834 
   1835             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
   1836             if ( !p || Attribute( attrib->Name() ) ) {
   1837                 DeleteAttribute( attrib );
   1838                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
   1839                 return 0;
   1840             }
   1841             // There is a minor bug here: if the attribute in the source xml
   1842             // document is duplicated, it will not be detected and the
   1843             // attribute will be doubly added. However, tracking the 'prevAttribute'
   1844             // avoids re-scanning the attribute list. Preferring performance for
   1845             // now, may reconsider in the future.
   1846             if ( prevAttribute ) {
   1847                 TIXMLASSERT( prevAttribute->_next == 0 );
   1848                 prevAttribute->_next = attrib;
   1849             }
   1850             else {
   1851                 TIXMLASSERT( _rootAttribute == 0 );
   1852                 _rootAttribute = attrib;
   1853             }
   1854             prevAttribute = attrib;
   1855         }
   1856         // end of the tag
   1857         else if ( *p == '>' ) {
   1858             ++p;
   1859             break;
   1860         }
   1861         // end of the tag
   1862         else if ( *p == '/' && *(p+1) == '>' ) {
   1863             _closingType = CLOSED;
   1864             return p+2;	// done; sealed element.
   1865         }
   1866         else {
   1867             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
   1868             return 0;
   1869         }
   1870     }
   1871     return p;
   1872 }
   1873 
   1874 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
   1875 {
   1876     if ( attribute == 0 ) {
   1877         return;
   1878     }
   1879     MemPool* pool = attribute->_memPool;
   1880     attribute->~XMLAttribute();
   1881     pool->Free( attribute );
   1882 }
   1883 
   1884 XMLAttribute* XMLElement::CreateAttribute()
   1885 {
   1886     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
   1887     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
   1888     TIXMLASSERT( attrib );
   1889     attrib->_memPool = &_document->_attributePool;
   1890     attrib->_memPool->SetTracked();
   1891     return attrib;
   1892 }
   1893 
   1894 //
   1895 //	<ele></ele>
   1896 //	<ele>foo<b>bar</b></ele>
   1897 //
   1898 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
   1899 {
   1900     // Read the element name.
   1901     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
   1902 
   1903     // The closing element is the </element> form. It is
   1904     // parsed just like a regular element then deleted from
   1905     // the DOM.
   1906     if ( *p == '/' ) {
   1907         _closingType = CLOSING;
   1908         ++p;
   1909     }
   1910 
   1911     p = _value.ParseName( p );
   1912     if ( _value.Empty() ) {
   1913         return 0;
   1914     }
   1915 
   1916     p = ParseAttributes( p, curLineNumPtr );
   1917     if ( !p || !*p || _closingType != OPEN ) {
   1918         return p;
   1919     }
   1920 
   1921     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
   1922     return p;
   1923 }
   1924 
   1925 
   1926 
   1927 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
   1928 {
   1929     if ( !doc ) {
   1930         doc = _document;
   1931     }
   1932     XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
   1933     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
   1934         element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
   1935     }
   1936     return element;
   1937 }
   1938 
   1939 
   1940 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
   1941 {
   1942     TIXMLASSERT( compare );
   1943     const XMLElement* other = compare->ToElement();
   1944     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
   1945 
   1946         const XMLAttribute* a=FirstAttribute();
   1947         const XMLAttribute* b=other->FirstAttribute();
   1948 
   1949         while ( a && b ) {
   1950             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
   1951                 return false;
   1952             }
   1953             a = a->Next();
   1954             b = b->Next();
   1955         }
   1956         if ( a || b ) {
   1957             // different count
   1958             return false;
   1959         }
   1960         return true;
   1961     }
   1962     return false;
   1963 }
   1964 
   1965 
   1966 bool XMLElement::Accept( XMLVisitor* visitor ) const
   1967 {
   1968     TIXMLASSERT( visitor );
   1969     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
   1970         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
   1971             if ( !node->Accept( visitor ) ) {
   1972                 break;
   1973             }
   1974         }
   1975     }
   1976     return visitor->VisitExit( *this );
   1977 }
   1978 
   1979 
   1980 // --------- XMLDocument ----------- //
   1981 
   1982 // Warning: List must match 'enum XMLError'
   1983 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
   1984     "XML_SUCCESS",
   1985     "XML_NO_ATTRIBUTE",
   1986     "XML_WRONG_ATTRIBUTE_TYPE",
   1987     "XML_ERROR_FILE_NOT_FOUND",
   1988     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
   1989     "XML_ERROR_FILE_READ_ERROR",
   1990     "XML_ERROR_PARSING_ELEMENT",
   1991     "XML_ERROR_PARSING_ATTRIBUTE",
   1992     "XML_ERROR_PARSING_TEXT",
   1993     "XML_ERROR_PARSING_CDATA",
   1994     "XML_ERROR_PARSING_COMMENT",
   1995     "XML_ERROR_PARSING_DECLARATION",
   1996     "XML_ERROR_PARSING_UNKNOWN",
   1997     "XML_ERROR_EMPTY_DOCUMENT",
   1998     "XML_ERROR_MISMATCHED_ELEMENT",
   1999     "XML_ERROR_PARSING",
   2000     "XML_CAN_NOT_CONVERT_TEXT",
   2001     "XML_NO_TEXT_NODE",
   2002 	"XML_ELEMENT_DEPTH_EXCEEDED"
   2003 };
   2004 
   2005 
   2006 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
   2007     XMLNode( 0 ),
   2008     _writeBOM( false ),
   2009     _processEntities( processEntities ),
   2010     _errorID(XML_SUCCESS),
   2011     _whitespaceMode( whitespaceMode ),
   2012     _errorStr(),
   2013     _errorLineNum( 0 ),
   2014     _charBuffer( 0 ),
   2015     _parseCurLineNum( 0 ),
   2016 	_parsingDepth(0),
   2017     _unlinked(),
   2018     _elementPool(),
   2019     _attributePool(),
   2020     _textPool(),
   2021     _commentPool()
   2022 {
   2023     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
   2024     _document = this;
   2025 }
   2026 
   2027 
   2028 XMLDocument::~XMLDocument()
   2029 {
   2030     Clear();
   2031 }
   2032 
   2033 
   2034 void XMLDocument::MarkInUse(XMLNode* node)
   2035 {
   2036 	TIXMLASSERT(node);
   2037 	TIXMLASSERT(node->_parent == 0);
   2038 
   2039 	for (int i = 0; i < _unlinked.Size(); ++i) {
   2040 		if (node == _unlinked[i]) {
   2041 			_unlinked.SwapRemove(i);
   2042 			break;
   2043 		}
   2044 	}
   2045 }
   2046 
   2047 void XMLDocument::Clear()
   2048 {
   2049     DeleteChildren();
   2050 	while( _unlinked.Size()) {
   2051 		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.
   2052 	}
   2053 
   2054 #ifdef TINYXML2_DEBUG
   2055     const bool hadError = Error();
   2056 #endif
   2057     ClearError();
   2058 
   2059     delete [] _charBuffer;
   2060     _charBuffer = 0;
   2061 	_parsingDepth = 0;
   2062 
   2063 #if 0
   2064     _textPool.Trace( "text" );
   2065     _elementPool.Trace( "element" );
   2066     _commentPool.Trace( "comment" );
   2067     _attributePool.Trace( "attribute" );
   2068 #endif
   2069 
   2070 #ifdef TINYXML2_DEBUG
   2071     if ( !hadError ) {
   2072         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
   2073         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
   2074         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
   2075         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
   2076     }
   2077 #endif
   2078 }
   2079 
   2080 
   2081 void XMLDocument::DeepCopy(XMLDocument* target) const
   2082 {
   2083 	TIXMLASSERT(target);
   2084     if (target == this) {
   2085         return; // technically success - a no-op.
   2086     }
   2087 
   2088 	target->Clear();
   2089 	for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
   2090 		target->InsertEndChild(node->DeepClone(target));
   2091 	}
   2092 }
   2093 
   2094 XMLElement* XMLDocument::NewElement( const char* name )
   2095 {
   2096     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
   2097     ele->SetName( name );
   2098     return ele;
   2099 }
   2100 
   2101 
   2102 XMLComment* XMLDocument::NewComment( const char* str )
   2103 {
   2104     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
   2105     comment->SetValue( str );
   2106     return comment;
   2107 }
   2108 
   2109 
   2110 XMLText* XMLDocument::NewText( const char* str )
   2111 {
   2112     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
   2113     text->SetValue( str );
   2114     return text;
   2115 }
   2116 
   2117 
   2118 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
   2119 {
   2120     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
   2121     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
   2122     return dec;
   2123 }
   2124 
   2125 
   2126 XMLUnknown* XMLDocument::NewUnknown( const char* str )
   2127 {
   2128     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
   2129     unk->SetValue( str );
   2130     return unk;
   2131 }
   2132 
   2133 static FILE* callfopen( const char* filepath, const char* mode )
   2134 {
   2135     TIXMLASSERT( filepath );
   2136     TIXMLASSERT( mode );
   2137 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
   2138     FILE* fp = 0;
   2139     errno_t err = fopen_s( &fp, filepath, mode );
   2140     if ( err ) {
   2141         return 0;
   2142     }
   2143 #else
   2144     FILE* fp = fopen( filepath, mode );
   2145 #endif
   2146     return fp;
   2147 }
   2148 
   2149 void XMLDocument::DeleteNode( XMLNode* node )	{
   2150     TIXMLASSERT( node );
   2151     TIXMLASSERT(node->_document == this );
   2152     if (node->_parent) {
   2153         node->_parent->DeleteChild( node );
   2154     }
   2155     else {
   2156         // Isn't in the tree.
   2157         // Use the parent delete.
   2158         // Also, we need to mark it tracked: we 'know'
   2159         // it was never used.
   2160         node->_memPool->SetTracked();
   2161         // Call the static XMLNode version:
   2162         XMLNode::DeleteNode(node);
   2163     }
   2164 }
   2165 
   2166 
   2167 XMLError XMLDocument::LoadFile( const char* filename )
   2168 {
   2169     if ( !filename ) {
   2170         TIXMLASSERT( false );
   2171         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
   2172         return _errorID;
   2173     }
   2174 
   2175     Clear();
   2176     FILE* fp = callfopen( filename, "rb" );
   2177     if ( !fp ) {
   2178         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
   2179         return _errorID;
   2180     }
   2181     LoadFile( fp );
   2182     fclose( fp );
   2183     return _errorID;
   2184 }
   2185 
   2186 // This is likely overengineered template art to have a check that unsigned long value incremented
   2187 // by one still fits into size_t. If size_t type is larger than unsigned long type
   2188 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
   2189 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
   2190 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
   2191 // types sizes relate to each other.
   2192 template
   2193 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
   2194 struct LongFitsIntoSizeTMinusOne {
   2195     static bool Fits( unsigned long value )
   2196     {
   2197         return value < (size_t)-1;
   2198     }
   2199 };
   2200 
   2201 template <>
   2202 struct LongFitsIntoSizeTMinusOne<false> {
   2203     static bool Fits( unsigned long )
   2204     {
   2205         return true;
   2206     }
   2207 };
   2208 
   2209 XMLError XMLDocument::LoadFile( FILE* fp )
   2210 {
   2211     Clear();
   2212 
   2213     fseek( fp, 0, SEEK_SET );
   2214     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
   2215         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
   2216         return _errorID;
   2217     }
   2218 
   2219     fseek( fp, 0, SEEK_END );
   2220     const long filelength = ftell( fp );
   2221     fseek( fp, 0, SEEK_SET );
   2222     if ( filelength == -1L ) {
   2223         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
   2224         return _errorID;
   2225     }
   2226     TIXMLASSERT( filelength >= 0 );
   2227 
   2228     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
   2229         // Cannot handle files which won't fit in buffer together with null terminator
   2230         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
   2231         return _errorID;
   2232     }
   2233 
   2234     if ( filelength == 0 ) {
   2235         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   2236         return _errorID;
   2237     }
   2238 
   2239     const size_t size = filelength;
   2240     TIXMLASSERT( _charBuffer == 0 );
   2241     _charBuffer = new char[size+1];
   2242     size_t read = fread( _charBuffer, 1, size, fp );
   2243     if ( read != size ) {
   2244         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
   2245         return _errorID;
   2246     }
   2247 
   2248     _charBuffer[size] = 0;
   2249 
   2250     Parse();
   2251     return _errorID;
   2252 }
   2253 
   2254 
   2255 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
   2256 {
   2257     if ( !filename ) {
   2258         TIXMLASSERT( false );
   2259         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
   2260         return _errorID;
   2261     }
   2262 
   2263     FILE* fp = callfopen( filename, "w" );
   2264     if ( !fp ) {
   2265         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
   2266         return _errorID;
   2267     }
   2268     SaveFile(fp, compact);
   2269     fclose( fp );
   2270     return _errorID;
   2271 }
   2272 
   2273 
   2274 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
   2275 {
   2276     // Clear any error from the last save, otherwise it will get reported
   2277     // for *this* call.
   2278     ClearError();
   2279     XMLPrinter stream( fp, compact );
   2280     Print( &stream );
   2281     return _errorID;
   2282 }
   2283 
   2284 
   2285 XMLError XMLDocument::Parse( const char* p, size_t len )
   2286 {
   2287     Clear();
   2288 
   2289     if ( len == 0 || !p || !*p ) {
   2290         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   2291         return _errorID;
   2292     }
   2293     if ( len == (size_t)(-1) ) {
   2294         len = strlen( p );
   2295     }
   2296     TIXMLASSERT( _charBuffer == 0 );
   2297     _charBuffer = new char[ len+1 ];
   2298     memcpy( _charBuffer, p, len );
   2299     _charBuffer[len] = 0;
   2300 
   2301     Parse();
   2302     if ( Error() ) {
   2303         // clean up now essentially dangling memory.
   2304         // and the parse fail can put objects in the
   2305         // pools that are dead and inaccessible.
   2306         DeleteChildren();
   2307         _elementPool.Clear();
   2308         _attributePool.Clear();
   2309         _textPool.Clear();
   2310         _commentPool.Clear();
   2311     }
   2312     return _errorID;
   2313 }
   2314 
   2315 
   2316 void XMLDocument::Print( XMLPrinter* streamer ) const
   2317 {
   2318     if ( streamer ) {
   2319         Accept( streamer );
   2320     }
   2321     else {
   2322         XMLPrinter stdoutStreamer( stdout );
   2323         Accept( &stdoutStreamer );
   2324     }
   2325 }
   2326 
   2327 
   2328 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
   2329 {
   2330     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
   2331     _errorID = error;
   2332     _errorLineNum = lineNum;
   2333 	_errorStr.Reset();
   2334 
   2335     size_t BUFFER_SIZE = 1000;
   2336     char* buffer = new char[BUFFER_SIZE];
   2337 
   2338     TIXMLASSERT(sizeof(error) <= sizeof(int));
   2339     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
   2340 
   2341 	if (format) {
   2342 		size_t len = strlen(buffer);
   2343 		TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
   2344 		len = strlen(buffer);
   2345 
   2346 		va_list va;
   2347 		va_start(va, format);
   2348 		TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
   2349 		va_end(va);
   2350 	}
   2351 	_errorStr.SetStr(buffer);
   2352 	delete[] buffer;
   2353 }
   2354 
   2355 
   2356 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
   2357 {
   2358 	TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
   2359     const char* errorName = _errorNames[errorID];
   2360     TIXMLASSERT( errorName && errorName[0] );
   2361     return errorName;
   2362 }
   2363 
   2364 const char* XMLDocument::ErrorStr() const
   2365 {
   2366 	return _errorStr.Empty() ? "" : _errorStr.GetStr();
   2367 }
   2368 
   2369 
   2370 void XMLDocument::PrintError() const
   2371 {
   2372     printf("%s\n", ErrorStr());
   2373 }
   2374 
   2375 const char* XMLDocument::ErrorName() const
   2376 {
   2377     return ErrorIDToName(_errorID);
   2378 }
   2379 
   2380 void XMLDocument::Parse()
   2381 {
   2382     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
   2383     TIXMLASSERT( _charBuffer );
   2384     _parseCurLineNum = 1;
   2385     _parseLineNum = 1;
   2386     char* p = _charBuffer;
   2387     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
   2388     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
   2389     if ( !*p ) {
   2390         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
   2391         return;
   2392     }
   2393     ParseDeep(p, 0, &_parseCurLineNum );
   2394 }
   2395 
   2396 void XMLDocument::PushDepth()
   2397 {
   2398 	_parsingDepth++;
   2399 	if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
   2400 		SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
   2401 	}
   2402 }
   2403 
   2404 void XMLDocument::PopDepth()
   2405 {
   2406 	TIXMLASSERT(_parsingDepth > 0);
   2407 	--_parsingDepth;
   2408 }
   2409 
   2410 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
   2411     _elementJustOpened( false ),
   2412     _stack(),
   2413     _firstElement( true ),
   2414     _fp( file ),
   2415     _depth( depth ),
   2416     _textDepth( -1 ),
   2417     _processEntities( true ),
   2418     _compactMode( compact ),
   2419     _buffer()
   2420 {
   2421     for( int i=0; i<ENTITY_RANGE; ++i ) {
   2422         _entityFlag[i] = false;
   2423         _restrictedEntityFlag[i] = false;
   2424     }
   2425     for( int i=0; i<NUM_ENTITIES; ++i ) {
   2426         const char entityValue = entities[i].value;
   2427         const unsigned char flagIndex = (unsigned char)entityValue;
   2428         TIXMLASSERT( flagIndex < ENTITY_RANGE );
   2429         _entityFlag[flagIndex] = true;
   2430     }
   2431     _restrictedEntityFlag[(unsigned char)'&'] = true;
   2432     _restrictedEntityFlag[(unsigned char)'<'] = true;
   2433     _restrictedEntityFlag[(unsigned char)'>'] = true;	// not required, but consistency is nice
   2434     _buffer.Push( 0 );
   2435 }
   2436 
   2437 
   2438 void XMLPrinter::Print( const char* format, ... )
   2439 {
   2440     va_list     va;
   2441     va_start( va, format );
   2442 
   2443     if ( _fp ) {
   2444         vfprintf( _fp, format, va );
   2445     }
   2446     else {
   2447         const int len = TIXML_VSCPRINTF( format, va );
   2448         // Close out and re-start the va-args
   2449         va_end( va );
   2450         TIXMLASSERT( len >= 0 );
   2451         va_start( va, format );
   2452         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
   2453         char* p = _buffer.PushArr( len ) - 1;	// back up over the null terminator.
   2454 		TIXML_VSNPRINTF( p, len+1, format, va );
   2455     }
   2456     va_end( va );
   2457 }
   2458 
   2459 
   2460 void XMLPrinter::Write( const char* data, size_t size )
   2461 {
   2462     if ( _fp ) {
   2463         fwrite ( data , sizeof(char), size, _fp);
   2464     }
   2465     else {
   2466         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
   2467         memcpy( p, data, size );
   2468         p[size] = 0;
   2469     }
   2470 }
   2471 
   2472 
   2473 void XMLPrinter::Putc( char ch )
   2474 {
   2475     if ( _fp ) {
   2476         fputc ( ch, _fp);
   2477     }
   2478     else {
   2479         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
   2480         p[0] = ch;
   2481         p[1] = 0;
   2482     }
   2483 }
   2484 
   2485 
   2486 void XMLPrinter::PrintSpace( int depth )
   2487 {
   2488     for( int i=0; i<depth; ++i ) {
   2489         Write( "    " );
   2490     }
   2491 }
   2492 
   2493 
   2494 void XMLPrinter::PrintString( const char* p, bool restricted )
   2495 {
   2496     // Look for runs of bytes between entities to print.
   2497     const char* q = p;
   2498 
   2499     if ( _processEntities ) {
   2500         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
   2501         while ( *q ) {
   2502             TIXMLASSERT( p <= q );
   2503             // Remember, char is sometimes signed. (How many times has that bitten me?)
   2504             if ( *q > 0 && *q < ENTITY_RANGE ) {
   2505                 // Check for entities. If one is found, flush
   2506                 // the stream up until the entity, write the
   2507                 // entity, and keep looking.
   2508                 if ( flag[(unsigned char)(*q)] ) {
   2509                     while ( p < q ) {
   2510                         const size_t delta = q - p;
   2511                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
   2512                         Write( p, toPrint );
   2513                         p += toPrint;
   2514                     }
   2515                     bool entityPatternPrinted = false;
   2516                     for( int i=0; i<NUM_ENTITIES; ++i ) {
   2517                         if ( entities[i].value == *q ) {
   2518                             Putc( '&' );
   2519                             Write( entities[i].pattern, entities[i].length );
   2520                             Putc( ';' );
   2521                             entityPatternPrinted = true;
   2522                             break;
   2523                         }
   2524                     }
   2525                     if ( !entityPatternPrinted ) {
   2526                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
   2527                         TIXMLASSERT( false );
   2528                     }
   2529                     ++p;
   2530                 }
   2531             }
   2532             ++q;
   2533             TIXMLASSERT( p <= q );
   2534         }
   2535         // Flush the remaining string. This will be the entire
   2536         // string if an entity wasn't found.
   2537         if ( p < q ) {
   2538             const size_t delta = q - p;
   2539             const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
   2540             Write( p, toPrint );
   2541         }
   2542     }
   2543     else {
   2544         Write( p );
   2545     }
   2546 }
   2547 
   2548 
   2549 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
   2550 {
   2551     if ( writeBOM ) {
   2552         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
   2553         Write( reinterpret_cast< const char* >( bom ) );
   2554     }
   2555     if ( writeDec ) {
   2556         PushDeclaration( "xml version=\"1.0\"" );
   2557     }
   2558 }
   2559 
   2560 
   2561 void XMLPrinter::OpenElement( const char* name, bool compactMode )
   2562 {
   2563     SealElementIfJustOpened();
   2564     _stack.Push( name );
   2565 
   2566     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
   2567         Putc( '\n' );
   2568     }
   2569     if ( !compactMode ) {
   2570         PrintSpace( _depth );
   2571     }
   2572 
   2573     Write ( "<" );
   2574     Write ( name );
   2575 
   2576     _elementJustOpened = true;
   2577     _firstElement = false;
   2578     ++_depth;
   2579 }
   2580 
   2581 
   2582 void XMLPrinter::PushAttribute( const char* name, const char* value )
   2583 {
   2584     TIXMLASSERT( _elementJustOpened );
   2585     Putc ( ' ' );
   2586     Write( name );
   2587     Write( "=\"" );
   2588     PrintString( value, false );
   2589     Putc ( '\"' );
   2590 }
   2591 
   2592 
   2593 void XMLPrinter::PushAttribute( const char* name, int v )
   2594 {
   2595     char buf[BUF_SIZE];
   2596     XMLUtil::ToStr( v, buf, BUF_SIZE );
   2597     PushAttribute( name, buf );
   2598 }
   2599 
   2600 
   2601 void XMLPrinter::PushAttribute( const char* name, unsigned v )
   2602 {
   2603     char buf[BUF_SIZE];
   2604     XMLUtil::ToStr( v, buf, BUF_SIZE );
   2605     PushAttribute( name, buf );
   2606 }
   2607 
   2608 
   2609 void XMLPrinter::PushAttribute(const char* name, int64_t v)
   2610 {
   2611 	char buf[BUF_SIZE];
   2612 	XMLUtil::ToStr(v, buf, BUF_SIZE);
   2613 	PushAttribute(name, buf);
   2614 }
   2615 
   2616 
   2617 void XMLPrinter::PushAttribute( const char* name, bool v )
   2618 {
   2619     char buf[BUF_SIZE];
   2620     XMLUtil::ToStr( v, buf, BUF_SIZE );
   2621     PushAttribute( name, buf );
   2622 }
   2623 
   2624 
   2625 void XMLPrinter::PushAttribute( const char* name, double v )
   2626 {
   2627     char buf[BUF_SIZE];
   2628     XMLUtil::ToStr( v, buf, BUF_SIZE );
   2629     PushAttribute( name, buf );
   2630 }
   2631 
   2632 
   2633 void XMLPrinter::CloseElement( bool compactMode )
   2634 {
   2635     --_depth;
   2636     const char* name = _stack.Pop();
   2637 
   2638     if ( _elementJustOpened ) {
   2639         Write( "/>" );
   2640     }
   2641     else {
   2642         if ( _textDepth < 0 && !compactMode) {
   2643             Putc( '\n' );
   2644             PrintSpace( _depth );
   2645         }
   2646         Write ( "</" );
   2647         Write ( name );
   2648         Write ( ">" );
   2649     }
   2650 
   2651     if ( _textDepth == _depth ) {
   2652         _textDepth = -1;
   2653     }
   2654     if ( _depth == 0 && !compactMode) {
   2655         Putc( '\n' );
   2656     }
   2657     _elementJustOpened = false;
   2658 }
   2659 
   2660 
   2661 void XMLPrinter::SealElementIfJustOpened()
   2662 {
   2663     if ( !_elementJustOpened ) {
   2664         return;
   2665     }
   2666     _elementJustOpened = false;
   2667     Putc( '>' );
   2668 }
   2669 
   2670 
   2671 void XMLPrinter::PushText( const char* text, bool cdata )
   2672 {
   2673     _textDepth = _depth-1;
   2674 
   2675     SealElementIfJustOpened();
   2676     if ( cdata ) {
   2677         Write( "<![CDATA[" );
   2678         Write( text );
   2679         Write( "]]>" );
   2680     }
   2681     else {
   2682         PrintString( text, true );
   2683     }
   2684 }
   2685 
   2686 void XMLPrinter::PushText( int64_t value )
   2687 {
   2688     char buf[BUF_SIZE];
   2689     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2690     PushText( buf, false );
   2691 }
   2692 
   2693 void XMLPrinter::PushText( int value )
   2694 {
   2695     char buf[BUF_SIZE];
   2696     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2697     PushText( buf, false );
   2698 }
   2699 
   2700 
   2701 void XMLPrinter::PushText( unsigned value )
   2702 {
   2703     char buf[BUF_SIZE];
   2704     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2705     PushText( buf, false );
   2706 }
   2707 
   2708 
   2709 void XMLPrinter::PushText( bool value )
   2710 {
   2711     char buf[BUF_SIZE];
   2712     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2713     PushText( buf, false );
   2714 }
   2715 
   2716 
   2717 void XMLPrinter::PushText( float value )
   2718 {
   2719     char buf[BUF_SIZE];
   2720     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2721     PushText( buf, false );
   2722 }
   2723 
   2724 
   2725 void XMLPrinter::PushText( double value )
   2726 {
   2727     char buf[BUF_SIZE];
   2728     XMLUtil::ToStr( value, buf, BUF_SIZE );
   2729     PushText( buf, false );
   2730 }
   2731 
   2732 
   2733 void XMLPrinter::PushComment( const char* comment )
   2734 {
   2735     SealElementIfJustOpened();
   2736     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
   2737         Putc( '\n' );
   2738         PrintSpace( _depth );
   2739     }
   2740     _firstElement = false;
   2741 
   2742     Write( "<!--" );
   2743     Write( comment );
   2744     Write( "-->" );
   2745 }
   2746 
   2747 
   2748 void XMLPrinter::PushDeclaration( const char* value )
   2749 {
   2750     SealElementIfJustOpened();
   2751     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
   2752         Putc( '\n' );
   2753         PrintSpace( _depth );
   2754     }
   2755     _firstElement = false;
   2756 
   2757     Write( "<?" );
   2758     Write( value );
   2759     Write( "?>" );
   2760 }
   2761 
   2762 
   2763 void XMLPrinter::PushUnknown( const char* value )
   2764 {
   2765     SealElementIfJustOpened();
   2766     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
   2767         Putc( '\n' );
   2768         PrintSpace( _depth );
   2769     }
   2770     _firstElement = false;
   2771 
   2772     Write( "<!" );
   2773     Write( value );
   2774     Putc( '>' );
   2775 }
   2776 
   2777 
   2778 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
   2779 {
   2780     _processEntities = doc.ProcessEntities();
   2781     if ( doc.HasBOM() ) {
   2782         PushHeader( true, false );
   2783     }
   2784     return true;
   2785 }
   2786 
   2787 
   2788 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
   2789 {
   2790     const XMLElement* parentElem = 0;
   2791     if ( element.Parent() ) {
   2792         parentElem = element.Parent()->ToElement();
   2793     }
   2794     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
   2795     OpenElement( element.Name(), compactMode );
   2796     while ( attribute ) {
   2797         PushAttribute( attribute->Name(), attribute->Value() );
   2798         attribute = attribute->Next();
   2799     }
   2800     return true;
   2801 }
   2802 
   2803 
   2804 bool XMLPrinter::VisitExit( const XMLElement& element )
   2805 {
   2806     CloseElement( CompactMode(element) );
   2807     return true;
   2808 }
   2809 
   2810 
   2811 bool XMLPrinter::Visit( const XMLText& text )
   2812 {
   2813     PushText( text.Value(), text.CData() );
   2814     return true;
   2815 }
   2816 
   2817 
   2818 bool XMLPrinter::Visit( const XMLComment& comment )
   2819 {
   2820     PushComment( comment.Value() );
   2821     return true;
   2822 }
   2823 
   2824 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
   2825 {
   2826     PushDeclaration( declaration.Value() );
   2827     return true;
   2828 }
   2829 
   2830 
   2831 bool XMLPrinter::Visit( const XMLUnknown& unknown )
   2832 {
   2833     PushUnknown( unknown.Value() );
   2834     return true;
   2835 }
   2836 
   2837 }   // namespace tinyxml2
   2838