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