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