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__) || defined(__DragonFly__)
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 (IsPrefixHex(str)) {
614         unsigned v;
615         if (TIXML_SSCANF(str, "%x", &v) == 1) {
616             *value = static_cast<int>(v);
617             return true;
618         }
619     }
620     else {
621         if (TIXML_SSCANF(str, "%d", value) == 1) {
622             return true;
623         }
624     }
625     return false;
626 }
627 
ToUnsigned(const char * str,unsigned * value)628 bool XMLUtil::ToUnsigned(const char* str, unsigned* value)
629 {
630     if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) {
631         return true;
632     }
633     return false;
634 }
635 
ToBool(const char * str,bool * value)636 bool XMLUtil::ToBool( const char* str, bool* value )
637 {
638     int ival = 0;
639     if ( ToInt( str, &ival )) {
640         *value = (ival==0) ? false : true;
641         return true;
642     }
643     static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
644     static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
645 
646     for (int i = 0; TRUE_VALS[i]; ++i) {
647         if (StringEqual(str, TRUE_VALS[i])) {
648             *value = true;
649             return true;
650         }
651     }
652     for (int i = 0; FALSE_VALS[i]; ++i) {
653         if (StringEqual(str, FALSE_VALS[i])) {
654             *value = false;
655             return true;
656         }
657     }
658     return false;
659 }
660 
661 
ToFloat(const char * str,float * value)662 bool XMLUtil::ToFloat( const char* str, float* value )
663 {
664     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
665         return true;
666     }
667     return false;
668 }
669 
670 
ToDouble(const char * str,double * value)671 bool XMLUtil::ToDouble( const char* str, double* value )
672 {
673     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
674         return true;
675     }
676     return false;
677 }
678 
679 
ToInt64(const char * str,int64_t * value)680 bool XMLUtil::ToInt64(const char* str, int64_t* value)
681 {
682     if (IsPrefixHex(str)) {
683         unsigned long long v = 0;	// horrible syntax trick to make the compiler happy about %llx
684         if (TIXML_SSCANF(str, "%llx", &v) == 1) {
685             *value = static_cast<int64_t>(v);
686             return true;
687         }
688     }
689     else {
690         long long v = 0;	// horrible syntax trick to make the compiler happy about %lld
691         if (TIXML_SSCANF(str, "%lld", &v) == 1) {
692             *value = static_cast<int64_t>(v);
693             return true;
694         }
695     }
696 	return false;
697 }
698 
699 
ToUnsigned64(const char * str,uint64_t * value)700 bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
701     unsigned long long v = 0;	// horrible syntax trick to make the compiler happy about %llu
702     if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
703         *value = (uint64_t)v;
704         return true;
705     }
706     return false;
707 }
708 
709 
Identify(char * p,XMLNode ** node)710 char* XMLDocument::Identify( char* p, XMLNode** node )
711 {
712     TIXMLASSERT( node );
713     TIXMLASSERT( p );
714     char* const start = p;
715     int const startLine = _parseCurLineNum;
716     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
717     if( !*p ) {
718         *node = 0;
719         TIXMLASSERT( p );
720         return p;
721     }
722 
723     // These strings define the matching patterns:
724     static const char* xmlHeader		= { "<?" };
725     static const char* commentHeader	= { "<!--" };
726     static const char* cdataHeader		= { "<![CDATA[" };
727     static const char* dtdHeader		= { "<!" };
728     static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
729 
730     static const int xmlHeaderLen		= 2;
731     static const int commentHeaderLen	= 4;
732     static const int cdataHeaderLen		= 9;
733     static const int dtdHeaderLen		= 2;
734     static const int elementHeaderLen	= 1;
735 
736     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
737     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
738     XMLNode* returnNode = 0;
739     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
740         returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
741         returnNode->_parseLineNum = _parseCurLineNum;
742         p += xmlHeaderLen;
743     }
744     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
745         returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
746         returnNode->_parseLineNum = _parseCurLineNum;
747         p += commentHeaderLen;
748     }
749     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
750         XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
751         returnNode = text;
752         returnNode->_parseLineNum = _parseCurLineNum;
753         p += cdataHeaderLen;
754         text->SetCData( true );
755     }
756     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
757         returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
758         returnNode->_parseLineNum = _parseCurLineNum;
759         p += dtdHeaderLen;
760     }
761     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
762         returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );
763         returnNode->_parseLineNum = _parseCurLineNum;
764         p += elementHeaderLen;
765     }
766     else {
767         returnNode = CreateUnlinkedNode<XMLText>( _textPool );
768         returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
769         p = start;	// Back it up, all the text counts.
770         _parseCurLineNum = startLine;
771     }
772 
773     TIXMLASSERT( returnNode );
774     TIXMLASSERT( p );
775     *node = returnNode;
776     return p;
777 }
778 
779 
Accept(XMLVisitor * visitor) const780 bool XMLDocument::Accept( XMLVisitor* visitor ) const
781 {
782     TIXMLASSERT( visitor );
783     if ( visitor->VisitEnter( *this ) ) {
784         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
785             if ( !node->Accept( visitor ) ) {
786                 break;
787             }
788         }
789     }
790     return visitor->VisitExit( *this );
791 }
792 
793 
794 // --------- XMLNode ----------- //
795 
XMLNode(XMLDocument * doc)796 XMLNode::XMLNode( XMLDocument* doc ) :
797     _document( doc ),
798     _parent( 0 ),
799     _value(),
800     _parseLineNum( 0 ),
801     _firstChild( 0 ), _lastChild( 0 ),
802     _prev( 0 ), _next( 0 ),
803 	_userData( 0 ),
804     _memPool( 0 )
805 {
806 }
807 
808 
~XMLNode()809 XMLNode::~XMLNode()
810 {
811     DeleteChildren();
812     if ( _parent ) {
813         _parent->Unlink( this );
814     }
815 }
816 
Value() const817 const char* XMLNode::Value() const
818 {
819     // Edge case: XMLDocuments don't have a Value. Return null.
820     if ( this->ToDocument() )
821         return 0;
822     return _value.GetStr();
823 }
824 
SetValue(const char * str,bool staticMem)825 void XMLNode::SetValue( const char* str, bool staticMem )
826 {
827     if ( staticMem ) {
828         _value.SetInternedStr( str );
829     }
830     else {
831         _value.SetStr( str );
832     }
833 }
834 
DeepClone(XMLDocument * target) const835 XMLNode* XMLNode::DeepClone(XMLDocument* target) const
836 {
837 	XMLNode* clone = this->ShallowClone(target);
838 	if (!clone) return 0;
839 
840 	for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
841 		XMLNode* childClone = child->DeepClone(target);
842 		TIXMLASSERT(childClone);
843 		clone->InsertEndChild(childClone);
844 	}
845 	return clone;
846 }
847 
DeleteChildren()848 void XMLNode::DeleteChildren()
849 {
850     while( _firstChild ) {
851         TIXMLASSERT( _lastChild );
852         DeleteChild( _firstChild );
853     }
854     _firstChild = _lastChild = 0;
855 }
856 
857 
Unlink(XMLNode * child)858 void XMLNode::Unlink( XMLNode* child )
859 {
860     TIXMLASSERT( child );
861     TIXMLASSERT( child->_document == _document );
862     TIXMLASSERT( child->_parent == this );
863     if ( child == _firstChild ) {
864         _firstChild = _firstChild->_next;
865     }
866     if ( child == _lastChild ) {
867         _lastChild = _lastChild->_prev;
868     }
869 
870     if ( child->_prev ) {
871         child->_prev->_next = child->_next;
872     }
873     if ( child->_next ) {
874         child->_next->_prev = child->_prev;
875     }
876 	child->_next = 0;
877 	child->_prev = 0;
878 	child->_parent = 0;
879 }
880 
881 
DeleteChild(XMLNode * node)882 void XMLNode::DeleteChild( XMLNode* node )
883 {
884     TIXMLASSERT( node );
885     TIXMLASSERT( node->_document == _document );
886     TIXMLASSERT( node->_parent == this );
887     Unlink( node );
888 	TIXMLASSERT(node->_prev == 0);
889 	TIXMLASSERT(node->_next == 0);
890 	TIXMLASSERT(node->_parent == 0);
891     DeleteNode( node );
892 }
893 
894 
InsertEndChild(XMLNode * addThis)895 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
896 {
897     TIXMLASSERT( addThis );
898     if ( addThis->_document != _document ) {
899         TIXMLASSERT( false );
900         return 0;
901     }
902     InsertChildPreamble( addThis );
903 
904     if ( _lastChild ) {
905         TIXMLASSERT( _firstChild );
906         TIXMLASSERT( _lastChild->_next == 0 );
907         _lastChild->_next = addThis;
908         addThis->_prev = _lastChild;
909         _lastChild = addThis;
910 
911         addThis->_next = 0;
912     }
913     else {
914         TIXMLASSERT( _firstChild == 0 );
915         _firstChild = _lastChild = addThis;
916 
917         addThis->_prev = 0;
918         addThis->_next = 0;
919     }
920     addThis->_parent = this;
921     return addThis;
922 }
923 
924 
InsertFirstChild(XMLNode * addThis)925 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
926 {
927     TIXMLASSERT( addThis );
928     if ( addThis->_document != _document ) {
929         TIXMLASSERT( false );
930         return 0;
931     }
932     InsertChildPreamble( addThis );
933 
934     if ( _firstChild ) {
935         TIXMLASSERT( _lastChild );
936         TIXMLASSERT( _firstChild->_prev == 0 );
937 
938         _firstChild->_prev = addThis;
939         addThis->_next = _firstChild;
940         _firstChild = addThis;
941 
942         addThis->_prev = 0;
943     }
944     else {
945         TIXMLASSERT( _lastChild == 0 );
946         _firstChild = _lastChild = addThis;
947 
948         addThis->_prev = 0;
949         addThis->_next = 0;
950     }
951     addThis->_parent = this;
952     return addThis;
953 }
954 
955 
InsertAfterChild(XMLNode * afterThis,XMLNode * addThis)956 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
957 {
958     TIXMLASSERT( addThis );
959     if ( addThis->_document != _document ) {
960         TIXMLASSERT( false );
961         return 0;
962     }
963 
964     TIXMLASSERT( afterThis );
965 
966     if ( afterThis->_parent != this ) {
967         TIXMLASSERT( false );
968         return 0;
969     }
970     if ( afterThis == addThis ) {
971         // Current state: BeforeThis -> AddThis -> OneAfterAddThis
972         // Now AddThis must disappear from it's location and then
973         // reappear between BeforeThis and OneAfterAddThis.
974         // So just leave it where it is.
975         return addThis;
976     }
977 
978     if ( afterThis->_next == 0 ) {
979         // The last node or the only node.
980         return InsertEndChild( addThis );
981     }
982     InsertChildPreamble( addThis );
983     addThis->_prev = afterThis;
984     addThis->_next = afterThis->_next;
985     afterThis->_next->_prev = addThis;
986     afterThis->_next = addThis;
987     addThis->_parent = this;
988     return addThis;
989 }
990 
991 
992 
993 
FirstChildElement(const char * name) const994 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
995 {
996     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
997         const XMLElement* element = node->ToElementWithName( name );
998         if ( element ) {
999             return element;
1000         }
1001     }
1002     return 0;
1003 }
1004 
1005 
LastChildElement(const char * name) const1006 const XMLElement* XMLNode::LastChildElement( const char* name ) const
1007 {
1008     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
1009         const XMLElement* element = node->ToElementWithName( name );
1010         if ( element ) {
1011             return element;
1012         }
1013     }
1014     return 0;
1015 }
1016 
1017 
NextSiblingElement(const char * name) const1018 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
1019 {
1020     for( const XMLNode* node = _next; node; node = node->_next ) {
1021         const XMLElement* element = node->ToElementWithName( name );
1022         if ( element ) {
1023             return element;
1024         }
1025     }
1026     return 0;
1027 }
1028 
1029 
PreviousSiblingElement(const char * name) const1030 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
1031 {
1032     for( const XMLNode* node = _prev; node; node = node->_prev ) {
1033         const XMLElement* element = node->ToElementWithName( name );
1034         if ( element ) {
1035             return element;
1036         }
1037     }
1038     return 0;
1039 }
1040 
1041 
ParseDeep(char * p,StrPair * parentEndTag,int * curLineNumPtr)1042 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
1043 {
1044     // This is a recursive method, but thinking about it "at the current level"
1045     // it is a pretty simple flat list:
1046     //		<foo/>
1047     //		<!-- comment -->
1048     //
1049     // With a special case:
1050     //		<foo>
1051     //		</foo>
1052     //		<!-- comment -->
1053     //
1054     // Where the closing element (/foo) *must* be the next thing after the opening
1055     // element, and the names must match. BUT the tricky bit is that the closing
1056     // element will be read by the child.
1057     //
1058     // 'endTag' is the end tag for this node, it is returned by a call to a child.
1059     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
1060 
1061 	XMLDocument::DepthTracker tracker(_document);
1062 	if (_document->Error())
1063 		return 0;
1064 
1065 	while( p && *p ) {
1066         XMLNode* node = 0;
1067 
1068         p = _document->Identify( p, &node );
1069         TIXMLASSERT( p );
1070         if ( node == 0 ) {
1071             break;
1072         }
1073 
1074        const int initialLineNum = node->_parseLineNum;
1075 
1076         StrPair endTag;
1077         p = node->ParseDeep( p, &endTag, curLineNumPtr );
1078         if ( !p ) {
1079             DeleteNode( node );
1080             if ( !_document->Error() ) {
1081                 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1082             }
1083             break;
1084         }
1085 
1086         const XMLDeclaration* const decl = node->ToDeclaration();
1087         if ( decl ) {
1088             // Declarations are only allowed at document level
1089             //
1090             // Multiple declarations are allowed but all declarations
1091             // must occur before anything else.
1092             //
1093             // Optimized due to a security test case. If the first node is
1094             // a declaration, and the last node is a declaration, then only
1095             // declarations have so far been added.
1096             bool wellLocated = false;
1097 
1098             if (ToDocument()) {
1099                 if (FirstChild()) {
1100                     wellLocated =
1101                         FirstChild() &&
1102                         FirstChild()->ToDeclaration() &&
1103                         LastChild() &&
1104                         LastChild()->ToDeclaration();
1105                 }
1106                 else {
1107                     wellLocated = true;
1108                 }
1109             }
1110             if ( !wellLocated ) {
1111                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1112                 DeleteNode( node );
1113                 break;
1114             }
1115         }
1116 
1117         XMLElement* ele = node->ToElement();
1118         if ( ele ) {
1119             // We read the end tag. Return it to the parent.
1120             if ( ele->ClosingType() == XMLElement::CLOSING ) {
1121                 if ( parentEndTag ) {
1122                     ele->_value.TransferTo( parentEndTag );
1123                 }
1124                 node->_memPool->SetTracked();   // created and then immediately deleted.
1125                 DeleteNode( node );
1126                 return p;
1127             }
1128 
1129             // Handle an end tag returned to this level.
1130             // And handle a bunch of annoying errors.
1131             bool mismatch = false;
1132             if ( endTag.Empty() ) {
1133                 if ( ele->ClosingType() == XMLElement::OPEN ) {
1134                     mismatch = true;
1135                 }
1136             }
1137             else {
1138                 if ( ele->ClosingType() != XMLElement::OPEN ) {
1139                     mismatch = true;
1140                 }
1141                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1142                     mismatch = true;
1143                 }
1144             }
1145             if ( mismatch ) {
1146                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1147                 DeleteNode( node );
1148                 break;
1149             }
1150         }
1151         InsertEndChild( node );
1152     }
1153     return 0;
1154 }
1155 
DeleteNode(XMLNode * node)1156 /*static*/ void XMLNode::DeleteNode( XMLNode* node )
1157 {
1158     if ( node == 0 ) {
1159         return;
1160     }
1161 	TIXMLASSERT(node->_document);
1162 	if (!node->ToDocument()) {
1163 		node->_document->MarkInUse(node);
1164 	}
1165 
1166     MemPool* pool = node->_memPool;
1167     node->~XMLNode();
1168     pool->Free( node );
1169 }
1170 
InsertChildPreamble(XMLNode * insertThis) const1171 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1172 {
1173     TIXMLASSERT( insertThis );
1174     TIXMLASSERT( insertThis->_document == _document );
1175 
1176 	if (insertThis->_parent) {
1177         insertThis->_parent->Unlink( insertThis );
1178 	}
1179 	else {
1180 		insertThis->_document->MarkInUse(insertThis);
1181         insertThis->_memPool->SetTracked();
1182 	}
1183 }
1184 
ToElementWithName(const char * name) const1185 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1186 {
1187     const XMLElement* element = this->ToElement();
1188     if ( element == 0 ) {
1189         return 0;
1190     }
1191     if ( name == 0 ) {
1192         return element;
1193     }
1194     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1195        return element;
1196     }
1197     return 0;
1198 }
1199 
1200 // --------- XMLText ---------- //
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1201 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1202 {
1203     if ( this->CData() ) {
1204         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1205         if ( !p ) {
1206             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1207         }
1208         return p;
1209     }
1210     else {
1211         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1212         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1213             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1214         }
1215 
1216         p = _value.ParseText( p, "<", flags, curLineNumPtr );
1217         if ( p && *p ) {
1218             return p-1;
1219         }
1220         if ( !p ) {
1221             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1222         }
1223     }
1224     return 0;
1225 }
1226 
1227 
ShallowClone(XMLDocument * doc) const1228 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1229 {
1230     if ( !doc ) {
1231         doc = _document;
1232     }
1233     XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
1234     text->SetCData( this->CData() );
1235     return text;
1236 }
1237 
1238 
ShallowEqual(const XMLNode * compare) const1239 bool XMLText::ShallowEqual( const XMLNode* compare ) const
1240 {
1241     TIXMLASSERT( compare );
1242     const XMLText* text = compare->ToText();
1243     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1244 }
1245 
1246 
Accept(XMLVisitor * visitor) const1247 bool XMLText::Accept( XMLVisitor* visitor ) const
1248 {
1249     TIXMLASSERT( visitor );
1250     return visitor->Visit( *this );
1251 }
1252 
1253 
1254 // --------- XMLComment ---------- //
1255 
XMLComment(XMLDocument * doc)1256 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1257 {
1258 }
1259 
1260 
~XMLComment()1261 XMLComment::~XMLComment()
1262 {
1263 }
1264 
1265 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1266 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1267 {
1268     // Comment parses as text.
1269     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1270     if ( p == 0 ) {
1271         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1272     }
1273     return p;
1274 }
1275 
1276 
ShallowClone(XMLDocument * doc) const1277 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1278 {
1279     if ( !doc ) {
1280         doc = _document;
1281     }
1282     XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
1283     return comment;
1284 }
1285 
1286 
ShallowEqual(const XMLNode * compare) const1287 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1288 {
1289     TIXMLASSERT( compare );
1290     const XMLComment* comment = compare->ToComment();
1291     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1292 }
1293 
1294 
Accept(XMLVisitor * visitor) const1295 bool XMLComment::Accept( XMLVisitor* visitor ) const
1296 {
1297     TIXMLASSERT( visitor );
1298     return visitor->Visit( *this );
1299 }
1300 
1301 
1302 // --------- XMLDeclaration ---------- //
1303 
XMLDeclaration(XMLDocument * doc)1304 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1305 {
1306 }
1307 
1308 
~XMLDeclaration()1309 XMLDeclaration::~XMLDeclaration()
1310 {
1311     //printf( "~XMLDeclaration\n" );
1312 }
1313 
1314 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1315 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1316 {
1317     // Declaration parses as text.
1318     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1319     if ( p == 0 ) {
1320         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1321     }
1322     return p;
1323 }
1324 
1325 
ShallowClone(XMLDocument * doc) const1326 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1327 {
1328     if ( !doc ) {
1329         doc = _document;
1330     }
1331     XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
1332     return dec;
1333 }
1334 
1335 
ShallowEqual(const XMLNode * compare) const1336 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1337 {
1338     TIXMLASSERT( compare );
1339     const XMLDeclaration* declaration = compare->ToDeclaration();
1340     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1341 }
1342 
1343 
1344 
Accept(XMLVisitor * visitor) const1345 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1346 {
1347     TIXMLASSERT( visitor );
1348     return visitor->Visit( *this );
1349 }
1350 
1351 // --------- XMLUnknown ---------- //
1352 
XMLUnknown(XMLDocument * doc)1353 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1354 {
1355 }
1356 
1357 
~XMLUnknown()1358 XMLUnknown::~XMLUnknown()
1359 {
1360 }
1361 
1362 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1363 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1364 {
1365     // Unknown parses as text.
1366     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1367     if ( !p ) {
1368         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1369     }
1370     return p;
1371 }
1372 
1373 
ShallowClone(XMLDocument * doc) const1374 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1375 {
1376     if ( !doc ) {
1377         doc = _document;
1378     }
1379     XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
1380     return text;
1381 }
1382 
1383 
ShallowEqual(const XMLNode * compare) const1384 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1385 {
1386     TIXMLASSERT( compare );
1387     const XMLUnknown* unknown = compare->ToUnknown();
1388     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1389 }
1390 
1391 
Accept(XMLVisitor * visitor) const1392 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1393 {
1394     TIXMLASSERT( visitor );
1395     return visitor->Visit( *this );
1396 }
1397 
1398 // --------- XMLAttribute ---------- //
1399 
Name() const1400 const char* XMLAttribute::Name() const
1401 {
1402     return _name.GetStr();
1403 }
1404 
Value() const1405 const char* XMLAttribute::Value() const
1406 {
1407     return _value.GetStr();
1408 }
1409 
ParseDeep(char * p,bool processEntities,int * curLineNumPtr)1410 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1411 {
1412     // Parse using the name rules: bug fix, was using ParseText before
1413     p = _name.ParseName( p );
1414     if ( !p || !*p ) {
1415         return 0;
1416     }
1417 
1418     // Skip white space before =
1419     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1420     if ( *p != '=' ) {
1421         return 0;
1422     }
1423 
1424     ++p;	// move up to opening quote
1425     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1426     if ( *p != '\"' && *p != '\'' ) {
1427         return 0;
1428     }
1429 
1430     const char endTag[2] = { *p, 0 };
1431     ++p;	// move past opening quote
1432 
1433     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1434     return p;
1435 }
1436 
1437 
SetName(const char * n)1438 void XMLAttribute::SetName( const char* n )
1439 {
1440     _name.SetStr( n );
1441 }
1442 
1443 
QueryIntValue(int * value) const1444 XMLError XMLAttribute::QueryIntValue( int* value ) const
1445 {
1446     if ( XMLUtil::ToInt( Value(), value )) {
1447         return XML_SUCCESS;
1448     }
1449     return XML_WRONG_ATTRIBUTE_TYPE;
1450 }
1451 
1452 
QueryUnsignedValue(unsigned int * value) const1453 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1454 {
1455     if ( XMLUtil::ToUnsigned( Value(), value )) {
1456         return XML_SUCCESS;
1457     }
1458     return XML_WRONG_ATTRIBUTE_TYPE;
1459 }
1460 
1461 
QueryInt64Value(int64_t * value) const1462 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1463 {
1464 	if (XMLUtil::ToInt64(Value(), value)) {
1465 		return XML_SUCCESS;
1466 	}
1467 	return XML_WRONG_ATTRIBUTE_TYPE;
1468 }
1469 
1470 
QueryUnsigned64Value(uint64_t * value) const1471 XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1472 {
1473     if(XMLUtil::ToUnsigned64(Value(), value)) {
1474         return XML_SUCCESS;
1475     }
1476     return XML_WRONG_ATTRIBUTE_TYPE;
1477 }
1478 
1479 
QueryBoolValue(bool * value) const1480 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1481 {
1482     if ( XMLUtil::ToBool( Value(), value )) {
1483         return XML_SUCCESS;
1484     }
1485     return XML_WRONG_ATTRIBUTE_TYPE;
1486 }
1487 
1488 
QueryFloatValue(float * value) const1489 XMLError XMLAttribute::QueryFloatValue( float* value ) const
1490 {
1491     if ( XMLUtil::ToFloat( Value(), value )) {
1492         return XML_SUCCESS;
1493     }
1494     return XML_WRONG_ATTRIBUTE_TYPE;
1495 }
1496 
1497 
QueryDoubleValue(double * value) const1498 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1499 {
1500     if ( XMLUtil::ToDouble( Value(), value )) {
1501         return XML_SUCCESS;
1502     }
1503     return XML_WRONG_ATTRIBUTE_TYPE;
1504 }
1505 
1506 
SetAttribute(const char * v)1507 void XMLAttribute::SetAttribute( const char* v )
1508 {
1509     _value.SetStr( v );
1510 }
1511 
1512 
SetAttribute(int v)1513 void XMLAttribute::SetAttribute( int v )
1514 {
1515     char buf[BUF_SIZE];
1516     XMLUtil::ToStr( v, buf, BUF_SIZE );
1517     _value.SetStr( buf );
1518 }
1519 
1520 
SetAttribute(unsigned v)1521 void XMLAttribute::SetAttribute( unsigned v )
1522 {
1523     char buf[BUF_SIZE];
1524     XMLUtil::ToStr( v, buf, BUF_SIZE );
1525     _value.SetStr( buf );
1526 }
1527 
1528 
SetAttribute(int64_t v)1529 void XMLAttribute::SetAttribute(int64_t v)
1530 {
1531 	char buf[BUF_SIZE];
1532 	XMLUtil::ToStr(v, buf, BUF_SIZE);
1533 	_value.SetStr(buf);
1534 }
1535 
SetAttribute(uint64_t v)1536 void XMLAttribute::SetAttribute(uint64_t v)
1537 {
1538     char buf[BUF_SIZE];
1539     XMLUtil::ToStr(v, buf, BUF_SIZE);
1540     _value.SetStr(buf);
1541 }
1542 
1543 
SetAttribute(bool v)1544 void XMLAttribute::SetAttribute( bool v )
1545 {
1546     char buf[BUF_SIZE];
1547     XMLUtil::ToStr( v, buf, BUF_SIZE );
1548     _value.SetStr( buf );
1549 }
1550 
SetAttribute(double v)1551 void XMLAttribute::SetAttribute( double v )
1552 {
1553     char buf[BUF_SIZE];
1554     XMLUtil::ToStr( v, buf, BUF_SIZE );
1555     _value.SetStr( buf );
1556 }
1557 
SetAttribute(float v)1558 void XMLAttribute::SetAttribute( float v )
1559 {
1560     char buf[BUF_SIZE];
1561     XMLUtil::ToStr( v, buf, BUF_SIZE );
1562     _value.SetStr( buf );
1563 }
1564 
1565 
1566 // --------- XMLElement ---------- //
XMLElement(XMLDocument * doc)1567 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1568     _closingType( OPEN ),
1569     _rootAttribute( 0 ),
1570     _appendedData( NULL ),
1571     _appendedDataSize( 0 )
1572 {
1573 }
1574 
1575 
~XMLElement()1576 XMLElement::~XMLElement()
1577 {
1578     while( _rootAttribute ) {
1579         XMLAttribute* next = _rootAttribute->_next;
1580         DeleteAttribute( _rootAttribute );
1581         _rootAttribute = next;
1582     }
1583     delete [] _appendedData;
1584 }
1585 
1586 
FindAttribute(const char * name) const1587 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1588 {
1589     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1590         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1591             return a;
1592         }
1593     }
1594     return 0;
1595 }
1596 
1597 
Attribute(const char * name,const char * value) const1598 const char* XMLElement::Attribute( const char* name, const char* value ) const
1599 {
1600     const XMLAttribute* a = FindAttribute( name );
1601     if ( !a ) {
1602         return 0;
1603     }
1604     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1605         return a->Value();
1606     }
1607     return 0;
1608 }
1609 
IntAttribute(const char * name,int defaultValue) const1610 int XMLElement::IntAttribute(const char* name, int defaultValue) const
1611 {
1612 	int i = defaultValue;
1613 	QueryIntAttribute(name, &i);
1614 	return i;
1615 }
1616 
UnsignedAttribute(const char * name,unsigned defaultValue) const1617 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1618 {
1619 	unsigned i = defaultValue;
1620 	QueryUnsignedAttribute(name, &i);
1621 	return i;
1622 }
1623 
Int64Attribute(const char * name,int64_t defaultValue) const1624 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1625 {
1626 	int64_t i = defaultValue;
1627 	QueryInt64Attribute(name, &i);
1628 	return i;
1629 }
1630 
Unsigned64Attribute(const char * name,uint64_t defaultValue) const1631 uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1632 {
1633 	uint64_t i = defaultValue;
1634 	QueryUnsigned64Attribute(name, &i);
1635 	return i;
1636 }
1637 
BoolAttribute(const char * name,bool defaultValue) const1638 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1639 {
1640 	bool b = defaultValue;
1641 	QueryBoolAttribute(name, &b);
1642 	return b;
1643 }
1644 
DoubleAttribute(const char * name,double defaultValue) const1645 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1646 {
1647 	double d = defaultValue;
1648 	QueryDoubleAttribute(name, &d);
1649 	return d;
1650 }
1651 
FloatAttribute(const char * name,float defaultValue) const1652 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1653 {
1654 	float f = defaultValue;
1655 	QueryFloatAttribute(name, &f);
1656 	return f;
1657 }
1658 
GetText() const1659 const char* XMLElement::GetText() const
1660 {
1661     if ( FirstChild() && FirstChild()->ToText() ) {
1662         return FirstChild()->Value();
1663     }
1664     return 0;
1665 }
1666 
1667 
SetText(const char * inText)1668 void	XMLElement::SetText( const char* inText )
1669 {
1670 	if ( FirstChild() && FirstChild()->ToText() )
1671 		FirstChild()->SetValue( inText );
1672 	else {
1673 		XMLText*	theText = GetDocument()->NewText( inText );
1674 		InsertFirstChild( theText );
1675 	}
1676 }
1677 
1678 
SetText(int v)1679 void XMLElement::SetText( int v )
1680 {
1681     char buf[BUF_SIZE];
1682     XMLUtil::ToStr( v, buf, BUF_SIZE );
1683     SetText( buf );
1684 }
1685 
1686 
SetText(unsigned v)1687 void XMLElement::SetText( unsigned v )
1688 {
1689     char buf[BUF_SIZE];
1690     XMLUtil::ToStr( v, buf, BUF_SIZE );
1691     SetText( buf );
1692 }
1693 
1694 
SetText(int64_t v)1695 void XMLElement::SetText(int64_t v)
1696 {
1697 	char buf[BUF_SIZE];
1698 	XMLUtil::ToStr(v, buf, BUF_SIZE);
1699 	SetText(buf);
1700 }
1701 
SetText(uint64_t v)1702 void XMLElement::SetText(uint64_t v) {
1703     char buf[BUF_SIZE];
1704     XMLUtil::ToStr(v, buf, BUF_SIZE);
1705     SetText(buf);
1706 }
1707 
1708 
SetText(bool v)1709 void XMLElement::SetText( bool v )
1710 {
1711     char buf[BUF_SIZE];
1712     XMLUtil::ToStr( v, buf, BUF_SIZE );
1713     SetText( buf );
1714 }
1715 
1716 
SetText(float v)1717 void XMLElement::SetText( float v )
1718 {
1719     char buf[BUF_SIZE];
1720     XMLUtil::ToStr( v, buf, BUF_SIZE );
1721     SetText( buf );
1722 }
1723 
1724 
SetText(double v)1725 void XMLElement::SetText( double v )
1726 {
1727     char buf[BUF_SIZE];
1728     XMLUtil::ToStr( v, buf, BUF_SIZE );
1729     SetText( buf );
1730 }
1731 
1732 
QueryIntText(int * ival) const1733 XMLError XMLElement::QueryIntText( int* ival ) const
1734 {
1735     if ( FirstChild() && FirstChild()->ToText() ) {
1736         const char* t = FirstChild()->Value();
1737         if ( XMLUtil::ToInt( t, ival ) ) {
1738             return XML_SUCCESS;
1739         }
1740         return XML_CAN_NOT_CONVERT_TEXT;
1741     }
1742     return XML_NO_TEXT_NODE;
1743 }
1744 
1745 
QueryUnsignedText(unsigned * uval) const1746 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1747 {
1748     if ( FirstChild() && FirstChild()->ToText() ) {
1749         const char* t = FirstChild()->Value();
1750         if ( XMLUtil::ToUnsigned( t, uval ) ) {
1751             return XML_SUCCESS;
1752         }
1753         return XML_CAN_NOT_CONVERT_TEXT;
1754     }
1755     return XML_NO_TEXT_NODE;
1756 }
1757 
1758 
QueryInt64Text(int64_t * ival) const1759 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1760 {
1761 	if (FirstChild() && FirstChild()->ToText()) {
1762 		const char* t = FirstChild()->Value();
1763 		if (XMLUtil::ToInt64(t, ival)) {
1764 			return XML_SUCCESS;
1765 		}
1766 		return XML_CAN_NOT_CONVERT_TEXT;
1767 	}
1768 	return XML_NO_TEXT_NODE;
1769 }
1770 
1771 
QueryUnsigned64Text(uint64_t * ival) const1772 XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const
1773 {
1774     if(FirstChild() && FirstChild()->ToText()) {
1775         const char* t = FirstChild()->Value();
1776         if(XMLUtil::ToUnsigned64(t, ival)) {
1777             return XML_SUCCESS;
1778         }
1779         return XML_CAN_NOT_CONVERT_TEXT;
1780     }
1781     return XML_NO_TEXT_NODE;
1782 }
1783 
1784 
QueryBoolText(bool * bval) const1785 XMLError XMLElement::QueryBoolText( bool* bval ) const
1786 {
1787     if ( FirstChild() && FirstChild()->ToText() ) {
1788         const char* t = FirstChild()->Value();
1789         if ( XMLUtil::ToBool( t, bval ) ) {
1790             return XML_SUCCESS;
1791         }
1792         return XML_CAN_NOT_CONVERT_TEXT;
1793     }
1794     return XML_NO_TEXT_NODE;
1795 }
1796 
1797 
QueryDoubleText(double * dval) const1798 XMLError XMLElement::QueryDoubleText( double* dval ) const
1799 {
1800     if ( FirstChild() && FirstChild()->ToText() ) {
1801         const char* t = FirstChild()->Value();
1802         if ( XMLUtil::ToDouble( t, dval ) ) {
1803             return XML_SUCCESS;
1804         }
1805         return XML_CAN_NOT_CONVERT_TEXT;
1806     }
1807     return XML_NO_TEXT_NODE;
1808 }
1809 
1810 
QueryFloatText(float * fval) const1811 XMLError XMLElement::QueryFloatText( float* fval ) const
1812 {
1813     if ( FirstChild() && FirstChild()->ToText() ) {
1814         const char* t = FirstChild()->Value();
1815         if ( XMLUtil::ToFloat( t, fval ) ) {
1816             return XML_SUCCESS;
1817         }
1818         return XML_CAN_NOT_CONVERT_TEXT;
1819     }
1820     return XML_NO_TEXT_NODE;
1821 }
1822 
IntText(int defaultValue) const1823 int XMLElement::IntText(int defaultValue) const
1824 {
1825 	int i = defaultValue;
1826 	QueryIntText(&i);
1827 	return i;
1828 }
1829 
UnsignedText(unsigned defaultValue) const1830 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1831 {
1832 	unsigned i = defaultValue;
1833 	QueryUnsignedText(&i);
1834 	return i;
1835 }
1836 
Int64Text(int64_t defaultValue) const1837 int64_t XMLElement::Int64Text(int64_t defaultValue) const
1838 {
1839 	int64_t i = defaultValue;
1840 	QueryInt64Text(&i);
1841 	return i;
1842 }
1843 
Unsigned64Text(uint64_t defaultValue) const1844 uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1845 {
1846 	uint64_t i = defaultValue;
1847 	QueryUnsigned64Text(&i);
1848 	return i;
1849 }
1850 
BoolText(bool defaultValue) const1851 bool XMLElement::BoolText(bool defaultValue) const
1852 {
1853 	bool b = defaultValue;
1854 	QueryBoolText(&b);
1855 	return b;
1856 }
1857 
DoubleText(double defaultValue) const1858 double XMLElement::DoubleText(double defaultValue) const
1859 {
1860 	double d = defaultValue;
1861 	QueryDoubleText(&d);
1862 	return d;
1863 }
1864 
FloatText(float defaultValue) const1865 float XMLElement::FloatText(float defaultValue) const
1866 {
1867 	float f = defaultValue;
1868 	QueryFloatText(&f);
1869 	return f;
1870 }
1871 
1872 
FindOrCreateAttribute(const char * name)1873 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1874 {
1875     XMLAttribute* last = 0;
1876     XMLAttribute* attrib = 0;
1877     for( attrib = _rootAttribute;
1878             attrib;
1879             last = attrib, attrib = attrib->_next ) {
1880         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1881             break;
1882         }
1883     }
1884     if ( !attrib ) {
1885         attrib = CreateAttribute();
1886         TIXMLASSERT( attrib );
1887         if ( last ) {
1888             TIXMLASSERT( last->_next == 0 );
1889             last->_next = attrib;
1890         }
1891         else {
1892             TIXMLASSERT( _rootAttribute == 0 );
1893             _rootAttribute = attrib;
1894         }
1895         attrib->SetName( name );
1896     }
1897     return attrib;
1898 }
1899 
1900 
DeleteAttribute(const char * name)1901 void XMLElement::DeleteAttribute( const char* name )
1902 {
1903     XMLAttribute* prev = 0;
1904     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1905         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1906             if ( prev ) {
1907                 prev->_next = a->_next;
1908             }
1909             else {
1910                 _rootAttribute = a->_next;
1911             }
1912             DeleteAttribute( a );
1913             break;
1914         }
1915         prev = a;
1916     }
1917 }
1918 
1919 
ParseAttributes(char * p,int * curLineNumPtr)1920 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
1921 {
1922     XMLAttribute* prevAttribute = 0;
1923 
1924     // Read the attributes.
1925     while( p ) {
1926         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1927         if ( !(*p) ) {
1928             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1929             return 0;
1930         }
1931 
1932         // attribute.
1933         if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
1934             XMLAttribute* attrib = CreateAttribute();
1935             TIXMLASSERT( attrib );
1936             attrib->_parseLineNum = _document->_parseCurLineNum;
1937 
1938             const int attrLineNum = attrib->_parseLineNum;
1939 
1940             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1941             if ( !p || Attribute( attrib->Name() ) ) {
1942                 DeleteAttribute( attrib );
1943                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1944                 return 0;
1945             }
1946             // There is a minor bug here: if the attribute in the source xml
1947             // document is duplicated, it will not be detected and the
1948             // attribute will be doubly added. However, tracking the 'prevAttribute'
1949             // avoids re-scanning the attribute list. Preferring performance for
1950             // now, may reconsider in the future.
1951             if ( prevAttribute ) {
1952                 TIXMLASSERT( prevAttribute->_next == 0 );
1953                 prevAttribute->_next = attrib;
1954             }
1955             else {
1956                 TIXMLASSERT( _rootAttribute == 0 );
1957                 _rootAttribute = attrib;
1958             }
1959             prevAttribute = attrib;
1960         }
1961         // end of the tag
1962         else if ( *p == '>' ) {
1963             ++p;
1964             break;
1965         }
1966         // end of the tag
1967         else if ( *p == '/' && *(p+1) == '>' ) {
1968             _closingType = CLOSED;
1969             return p+2;	// done; sealed element.
1970         }
1971         else {
1972             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
1973             return 0;
1974         }
1975     }
1976     return p;
1977 }
1978 
DeleteAttribute(XMLAttribute * attribute)1979 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1980 {
1981     if ( attribute == 0 ) {
1982         return;
1983     }
1984     MemPool* pool = attribute->_memPool;
1985     attribute->~XMLAttribute();
1986     pool->Free( attribute );
1987 }
1988 
CreateAttribute()1989 XMLAttribute* XMLElement::CreateAttribute()
1990 {
1991     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1992     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1993     TIXMLASSERT( attrib );
1994     attrib->_memPool = &_document->_attributePool;
1995     attrib->_memPool->SetTracked();
1996     return attrib;
1997 }
1998 
1999 
InsertNewChildElement(const char * name)2000 XMLElement* XMLElement::InsertNewChildElement(const char* name)
2001 {
2002     XMLElement* node = _document->NewElement(name);
2003     return InsertEndChild(node) ? node : 0;
2004 }
2005 
InsertNewComment(const char * comment)2006 XMLComment* XMLElement::InsertNewComment(const char* comment)
2007 {
2008     XMLComment* node = _document->NewComment(comment);
2009     return InsertEndChild(node) ? node : 0;
2010 }
2011 
InsertNewText(const char * text)2012 XMLText* XMLElement::InsertNewText(const char* text)
2013 {
2014     XMLText* node = _document->NewText(text);
2015     return InsertEndChild(node) ? node : 0;
2016 }
2017 
InsertNewDeclaration(const char * text)2018 XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
2019 {
2020     XMLDeclaration* node = _document->NewDeclaration(text);
2021     return InsertEndChild(node) ? node : 0;
2022 }
2023 
InsertNewUnknown(const char * text)2024 XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
2025 {
2026     XMLUnknown* node = _document->NewUnknown(text);
2027     return InsertEndChild(node) ? node : 0;
2028 }
2029 
2030 
2031 
2032 //
2033 //	<ele></ele>
2034 //	<ele>foo<b>bar</b></ele>
2035 //
ParseDeep(char * p,StrPair * parentEndTag,int * curLineNumPtr)2036 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
2037 {
2038     // Read the element name.
2039     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
2040 
2041     // The closing element is the </element> form. It is
2042     // parsed just like a regular element then deleted from
2043     // the DOM.
2044     if ( *p == '/' ) {
2045         _closingType = CLOSING;
2046         ++p;
2047     }
2048 
2049     p = _value.ParseName( p );
2050     if ( _value.Empty() ) {
2051         return 0;
2052     }
2053 
2054     p = ParseAttributes( p, curLineNumPtr );
2055     if ( !p || !*p || _closingType != OPEN ) {
2056         return p;
2057     }
2058 
2059     if ( XMLUtil::StringEqual( _value.GetStr(), "AppendedData", 12 )
2060             && _rootAttribute
2061             && XMLUtil::StringEqual( _rootAttribute->Name(), "encoding", 8 )
2062             && XMLUtil::StringEqual( _rootAttribute->Value(), "raw", 3 ) ) {
2063         char *appendedDataStart = p;
2064         while ( p < _document->_charBuffer + _document->_len )
2065         {
2066             if ( *p == '<' && XMLUtil::StringEqual( p, "</AppendedData>", 15 ) ) {
2067                 _appendedDataSize = p - appendedDataStart;
2068                 _appendedData = new char[_appendedDataSize];
2069                 memcpy(_appendedData, appendedDataStart, _appendedDataSize);
2070                 break;
2071             }
2072             ++p;
2073         }
2074         if (_appendedData == NULL)
2075         {
2076             _document->SetError(XML_ERROR_PARSING_APPENDED_DATA, _parseLineNum, 0);
2077         }
2078     }
2079 
2080     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2081     return p;
2082 }
2083 
2084 
2085 
ShallowClone(XMLDocument * doc) const2086 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2087 {
2088     if ( !doc ) {
2089         doc = _document;
2090     }
2091     XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
2092     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2093         element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
2094     }
2095     return element;
2096 }
2097 
2098 
ShallowEqual(const XMLNode * compare) const2099 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2100 {
2101     TIXMLASSERT( compare );
2102     const XMLElement* other = compare->ToElement();
2103     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
2104 
2105         const XMLAttribute* a=FirstAttribute();
2106         const XMLAttribute* b=other->FirstAttribute();
2107 
2108         while ( a && b ) {
2109             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2110                 return false;
2111             }
2112             a = a->Next();
2113             b = b->Next();
2114         }
2115         if ( a || b ) {
2116             // different count
2117             return false;
2118         }
2119         return true;
2120     }
2121     return false;
2122 }
2123 
2124 
Accept(XMLVisitor * visitor) const2125 bool XMLElement::Accept( XMLVisitor* visitor ) const
2126 {
2127     TIXMLASSERT( visitor );
2128     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
2129         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2130             if ( !node->Accept( visitor ) ) {
2131                 break;
2132             }
2133         }
2134     }
2135     return visitor->VisitExit( *this );
2136 }
2137 
2138 
2139 // --------- XMLDocument ----------- //
2140 
2141 // Warning: List must match 'enum XMLError'
2142 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2143     "XML_SUCCESS",
2144     "XML_NO_ATTRIBUTE",
2145     "XML_WRONG_ATTRIBUTE_TYPE",
2146     "XML_ERROR_FILE_NOT_FOUND",
2147     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2148     "XML_ERROR_FILE_READ_ERROR",
2149     "XML_ERROR_PARSING_ELEMENT",
2150     "XML_ERROR_PARSING_ATTRIBUTE",
2151     "XML_ERROR_PARSING_TEXT",
2152     "XML_ERROR_PARSING_CDATA",
2153     "XML_ERROR_PARSING_COMMENT",
2154     "XML_ERROR_PARSING_DECLARATION",
2155     "XML_ERROR_PARSING_UNKNOWN",
2156     "XML_ERROR_EMPTY_DOCUMENT",
2157     "XML_ERROR_MISMATCHED_ELEMENT",
2158     "XML_ERROR_PARSING",
2159     "XML_CAN_NOT_CONVERT_TEXT",
2160     "XML_NO_TEXT_NODE",
2161 	"XML_ELEMENT_DEPTH_EXCEEDED"
2162 };
2163 
2164 
XMLDocument(bool processEntities,Whitespace whitespaceMode)2165 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
2166     XMLNode( 0 ),
2167     _writeBOM( false ),
2168     _processEntities( processEntities ),
2169     _errorID(XML_SUCCESS),
2170     _whitespaceMode( whitespaceMode ),
2171     _errorStr(),
2172     _errorLineNum( 0 ),
2173     _charBuffer( 0 ),
2174     _len( 0 ),
2175     _parseCurLineNum( 0 ),
2176 	_parsingDepth(0),
2177     _unlinked(),
2178     _elementPool(),
2179     _attributePool(),
2180     _textPool(),
2181     _commentPool()
2182 {
2183     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2184     _document = this;
2185 }
2186 
2187 
~XMLDocument()2188 XMLDocument::~XMLDocument()
2189 {
2190     Clear();
2191 }
2192 
2193 
MarkInUse(const XMLNode * const node)2194 void XMLDocument::MarkInUse(const XMLNode* const node)
2195 {
2196 	TIXMLASSERT(node);
2197 	TIXMLASSERT(node->_parent == 0);
2198 
2199 	for (int i = 0; i < _unlinked.Size(); ++i) {
2200 		if (node == _unlinked[i]) {
2201 			_unlinked.SwapRemove(i);
2202 			break;
2203 		}
2204 	}
2205 }
2206 
Clear()2207 void XMLDocument::Clear()
2208 {
2209     DeleteChildren();
2210 	while( _unlinked.Size()) {
2211 		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.
2212 	}
2213 
2214 #ifdef TINYXML2_DEBUG
2215     const bool hadError = Error();
2216 #endif
2217     ClearError();
2218 
2219     delete [] _charBuffer;
2220     _charBuffer = 0;
2221 	_parsingDepth = 0;
2222 
2223 #if 0
2224     _textPool.Trace( "text" );
2225     _elementPool.Trace( "element" );
2226     _commentPool.Trace( "comment" );
2227     _attributePool.Trace( "attribute" );
2228 #endif
2229 
2230 #ifdef TINYXML2_DEBUG
2231     if ( !hadError ) {
2232         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
2233         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2234         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
2235         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
2236     }
2237 #endif
2238 }
2239 
2240 
DeepCopy(XMLDocument * target) const2241 void XMLDocument::DeepCopy(XMLDocument* target) const
2242 {
2243 	TIXMLASSERT(target);
2244     if (target == this) {
2245         return; // technically success - a no-op.
2246     }
2247 
2248 	target->Clear();
2249 	for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2250 		target->InsertEndChild(node->DeepClone(target));
2251 	}
2252 }
2253 
NewElement(const char * name)2254 XMLElement* XMLDocument::NewElement( const char* name )
2255 {
2256     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
2257     ele->SetName( name );
2258     return ele;
2259 }
2260 
2261 
NewComment(const char * str)2262 XMLComment* XMLDocument::NewComment( const char* str )
2263 {
2264     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
2265     comment->SetValue( str );
2266     return comment;
2267 }
2268 
2269 
NewText(const char * str)2270 XMLText* XMLDocument::NewText( const char* str )
2271 {
2272     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
2273     text->SetValue( str );
2274     return text;
2275 }
2276 
2277 
NewDeclaration(const char * str)2278 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2279 {
2280     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
2281     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2282     return dec;
2283 }
2284 
2285 
NewUnknown(const char * str)2286 XMLUnknown* XMLDocument::NewUnknown( const char* str )
2287 {
2288     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
2289     unk->SetValue( str );
2290     return unk;
2291 }
2292 
callfopen(const char * filepath,const char * mode)2293 static FILE* callfopen( const char* filepath, const char* mode )
2294 {
2295     TIXMLASSERT( filepath );
2296     TIXMLASSERT( mode );
2297 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2298     FILE* fp = 0;
2299     const errno_t err = fopen_s( &fp, filepath, mode );
2300     if ( err ) {
2301         return 0;
2302     }
2303 #else
2304     FILE* fp = fopen( filepath, mode );
2305 #endif
2306     return fp;
2307 }
2308 
DeleteNode(XMLNode * node)2309 void XMLDocument::DeleteNode( XMLNode* node )	{
2310     TIXMLASSERT( node );
2311     TIXMLASSERT(node->_document == this );
2312     if (node->_parent) {
2313         node->_parent->DeleteChild( node );
2314     }
2315     else {
2316         // Isn't in the tree.
2317         // Use the parent delete.
2318         // Also, we need to mark it tracked: we 'know'
2319         // it was never used.
2320         node->_memPool->SetTracked();
2321         // Call the static XMLNode version:
2322         XMLNode::DeleteNode(node);
2323     }
2324 }
2325 
2326 
LoadFile(const char * filename)2327 XMLError XMLDocument::LoadFile( const char* filename )
2328 {
2329     if ( !filename ) {
2330         TIXMLASSERT( false );
2331         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2332         return _errorID;
2333     }
2334 
2335     Clear();
2336     FILE* fp = callfopen( filename, "rb" );
2337     if ( !fp ) {
2338         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2339         return _errorID;
2340     }
2341     LoadFile( fp );
2342     fclose( fp );
2343     return _errorID;
2344 }
2345 
LoadFile(FILE * fp)2346 XMLError XMLDocument::LoadFile( FILE* fp )
2347 {
2348     Clear();
2349 
2350     TIXML_FSEEK( fp, 0, SEEK_SET );
2351     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2352         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2353         return _errorID;
2354     }
2355 
2356     TIXML_FSEEK( fp, 0, SEEK_END );
2357 
2358     unsigned long long filelength;
2359     {
2360         const long long fileLengthSigned = TIXML_FTELL( fp );
2361         TIXML_FSEEK( fp, 0, SEEK_SET );
2362         if ( fileLengthSigned == -1L ) {
2363             SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2364             return _errorID;
2365         }
2366         TIXMLASSERT( fileLengthSigned >= 0 );
2367         filelength = static_cast<unsigned long long>(fileLengthSigned);
2368     }
2369 
2370     const size_t maxSizeT = static_cast<size_t>(-1);
2371     // We'll do the comparison as an unsigned long long, because that's guaranteed to be at
2372     // least 8 bytes, even on a 32-bit platform.
2373     if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
2374         // Cannot handle files which won't fit in buffer together with null terminator
2375         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2376         return _errorID;
2377     }
2378 
2379     if ( filelength == 0 ) {
2380         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2381         return _errorID;
2382     }
2383 
2384     const size_t size = static_cast<size_t>(filelength);
2385     TIXMLASSERT( _charBuffer == 0 );
2386     _charBuffer = new char[size+1];
2387     const size_t read = fread( _charBuffer, 1, size, fp );
2388     if ( read != size ) {
2389         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2390         return _errorID;
2391     }
2392 
2393     _charBuffer[size] = 0;
2394     _len = size;
2395 
2396     Parse();
2397     return _errorID;
2398 }
2399 
2400 
SaveFile(const char * filename,bool compact)2401 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2402 {
2403     if ( !filename ) {
2404         TIXMLASSERT( false );
2405         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2406         return _errorID;
2407     }
2408 
2409     FILE* fp = callfopen( filename, "w" );
2410     if ( !fp ) {
2411         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
2412         return _errorID;
2413     }
2414     SaveFile(fp, compact);
2415     fclose( fp );
2416     return _errorID;
2417 }
2418 
2419 
SaveFile(FILE * fp,bool compact)2420 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2421 {
2422     // Clear any error from the last save, otherwise it will get reported
2423     // for *this* call.
2424     ClearError();
2425     XMLPrinter stream( fp, compact );
2426     Print( &stream );
2427     return _errorID;
2428 }
2429 
2430 
Parse(const char * p,size_t len)2431 XMLError XMLDocument::Parse( const char* p, size_t len )
2432 {
2433     Clear();
2434 
2435     if ( len == 0 || !p || !*p ) {
2436         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2437         return _errorID;
2438     }
2439     if ( len == static_cast<size_t>(-1) ) {
2440         len = strlen( p );
2441     }
2442     TIXMLASSERT( _charBuffer == 0 );
2443     _charBuffer = new char[ len+1 ];
2444     memcpy( _charBuffer, p, len );
2445     _charBuffer[len] = 0;
2446     _len = len;
2447 
2448     Parse();
2449     if ( Error() ) {
2450         // clean up now essentially dangling memory.
2451         // and the parse fail can put objects in the
2452         // pools that are dead and inaccessible.
2453         DeleteChildren();
2454         _elementPool.Clear();
2455         _attributePool.Clear();
2456         _textPool.Clear();
2457         _commentPool.Clear();
2458     }
2459     return _errorID;
2460 }
2461 
2462 
Print(XMLPrinter * streamer) const2463 void XMLDocument::Print( XMLPrinter* streamer ) const
2464 {
2465     if ( streamer ) {
2466         Accept( streamer );
2467     }
2468     else {
2469         XMLPrinter stdoutStreamer( stdout );
2470         Accept( &stdoutStreamer );
2471     }
2472 }
2473 
2474 
SetError(XMLError error,int lineNum,const char * format,...)2475 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2476 {
2477     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2478     _errorID = error;
2479     _errorLineNum = lineNum;
2480 	_errorStr.Reset();
2481 
2482     const size_t BUFFER_SIZE = 1000;
2483     char* buffer = new char[BUFFER_SIZE];
2484 
2485     TIXMLASSERT(sizeof(error) <= sizeof(int));
2486     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
2487 
2488 	if (format) {
2489 		size_t len = strlen(buffer);
2490 		TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2491 		len = strlen(buffer);
2492 
2493 		va_list va;
2494 		va_start(va, format);
2495 		TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2496 		va_end(va);
2497 	}
2498 	_errorStr.SetStr(buffer);
2499 	delete[] buffer;
2500 }
2501 
2502 
ErrorIDToName(XMLError errorID)2503 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2504 {
2505 	TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2506     const char* errorName = _errorNames[errorID];
2507     TIXMLASSERT( errorName && errorName[0] );
2508     return errorName;
2509 }
2510 
ErrorStr() const2511 const char* XMLDocument::ErrorStr() const
2512 {
2513 	return _errorStr.Empty() ? "" : _errorStr.GetStr();
2514 }
2515 
2516 
PrintError() const2517 void XMLDocument::PrintError() const
2518 {
2519     printf("%s\n", ErrorStr());
2520 }
2521 
ErrorName() const2522 const char* XMLDocument::ErrorName() const
2523 {
2524     return ErrorIDToName(_errorID);
2525 }
2526 
Parse()2527 void XMLDocument::Parse()
2528 {
2529     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2530     TIXMLASSERT( _charBuffer );
2531     _parseCurLineNum = 1;
2532     _parseLineNum = 1;
2533     char* p = _charBuffer;
2534     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2535     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2536     if ( !*p ) {
2537         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2538         return;
2539     }
2540     ParseDeep(p, 0, &_parseCurLineNum );
2541 }
2542 
PushDepth()2543 void XMLDocument::PushDepth()
2544 {
2545 	_parsingDepth++;
2546 	if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2547 		SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2548 	}
2549 }
2550 
PopDepth()2551 void XMLDocument::PopDepth()
2552 {
2553 	TIXMLASSERT(_parsingDepth > 0);
2554 	--_parsingDepth;
2555 }
2556 
XMLPrinter(FILE * file,bool compact,int depth)2557 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2558     _elementJustOpened( false ),
2559     _stack(),
2560     _firstElement( true ),
2561     _fp( file ),
2562     _depth( depth ),
2563     _textDepth( -1 ),
2564     _processEntities( true ),
2565     _compactMode( compact ),
2566     _buffer()
2567 {
2568     for( int i=0; i<ENTITY_RANGE; ++i ) {
2569         _entityFlag[i] = false;
2570         _restrictedEntityFlag[i] = false;
2571     }
2572     for( int i=0; i<NUM_ENTITIES; ++i ) {
2573         const char entityValue = entities[i].value;
2574         const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
2575         TIXMLASSERT( flagIndex < ENTITY_RANGE );
2576         _entityFlag[flagIndex] = true;
2577     }
2578     _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2579     _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2580     _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;	// not required, but consistency is nice
2581     _buffer.Push( 0 );
2582 }
2583 
2584 
Print(const char * format,...)2585 void XMLPrinter::Print( const char* format, ... )
2586 {
2587     va_list     va;
2588     va_start( va, format );
2589 
2590     if ( _fp ) {
2591         vfprintf( _fp, format, va );
2592     }
2593     else {
2594         const int len = TIXML_VSCPRINTF( format, va );
2595         // Close out and re-start the va-args
2596         va_end( va );
2597         TIXMLASSERT( len >= 0 );
2598         va_start( va, format );
2599         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2600         char* p = _buffer.PushArr( len ) - 1;	// back up over the null terminator.
2601 		TIXML_VSNPRINTF( p, len+1, format, va );
2602     }
2603     va_end( va );
2604 }
2605 
2606 
Write(const char * data,size_t size)2607 void XMLPrinter::Write( const char* data, size_t size )
2608 {
2609     if ( _fp ) {
2610         fwrite ( data , sizeof(char), size, _fp);
2611     }
2612     else {
2613         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
2614         memcpy( p, data, size );
2615         p[size] = 0;
2616     }
2617 }
2618 
2619 
Putc(char ch)2620 void XMLPrinter::Putc( char ch )
2621 {
2622     if ( _fp ) {
2623         fputc ( ch, _fp);
2624     }
2625     else {
2626         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
2627         p[0] = ch;
2628         p[1] = 0;
2629     }
2630 }
2631 
2632 
PrintSpace(int depth)2633 void XMLPrinter::PrintSpace( int depth )
2634 {
2635     for( int i=0; i<depth; ++i ) {
2636         Write( "    " );
2637     }
2638 }
2639 
2640 
PrintString(const char * p,bool restricted)2641 void XMLPrinter::PrintString( const char* p, bool restricted )
2642 {
2643     // Look for runs of bytes between entities to print.
2644     const char* q = p;
2645 
2646     if ( _processEntities ) {
2647         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2648         while ( *q ) {
2649             TIXMLASSERT( p <= q );
2650             // Remember, char is sometimes signed. (How many times has that bitten me?)
2651             if ( *q > 0 && *q < ENTITY_RANGE ) {
2652                 // Check for entities. If one is found, flush
2653                 // the stream up until the entity, write the
2654                 // entity, and keep looking.
2655                 if ( flag[static_cast<unsigned char>(*q)] ) {
2656                     while ( p < q ) {
2657                         const size_t delta = q - p;
2658                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2659                         Write( p, toPrint );
2660                         p += toPrint;
2661                     }
2662                     bool entityPatternPrinted = false;
2663                     for( int i=0; i<NUM_ENTITIES; ++i ) {
2664                         if ( entities[i].value == *q ) {
2665                             Putc( '&' );
2666                             Write( entities[i].pattern, entities[i].length );
2667                             Putc( ';' );
2668                             entityPatternPrinted = true;
2669                             break;
2670                         }
2671                     }
2672                     if ( !entityPatternPrinted ) {
2673                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2674                         TIXMLASSERT( false );
2675                     }
2676                     ++p;
2677                 }
2678             }
2679             ++q;
2680             TIXMLASSERT( p <= q );
2681         }
2682         // Flush the remaining string. This will be the entire
2683         // string if an entity wasn't found.
2684         if ( p < q ) {
2685             const size_t delta = q - p;
2686             const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2687             Write( p, toPrint );
2688         }
2689     }
2690     else {
2691         Write( p );
2692     }
2693 }
2694 
2695 
PushHeader(bool writeBOM,bool writeDec)2696 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2697 {
2698     if ( writeBOM ) {
2699         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2700         Write( reinterpret_cast< const char* >( bom ) );
2701     }
2702     if ( writeDec ) {
2703         PushDeclaration( "xml version=\"1.0\"" );
2704     }
2705 }
2706 
PrepareForNewNode(bool compactMode)2707 void XMLPrinter::PrepareForNewNode( bool compactMode )
2708 {
2709     SealElementIfJustOpened();
2710 
2711     if ( compactMode ) {
2712         return;
2713     }
2714 
2715     if ( _firstElement ) {
2716         PrintSpace (_depth);
2717     } else if ( _textDepth < 0) {
2718         Putc( '\n' );
2719         PrintSpace( _depth );
2720     }
2721 
2722     _firstElement = false;
2723 }
2724 
OpenElement(const char * name,bool compactMode)2725 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2726 {
2727     PrepareForNewNode( compactMode );
2728     _stack.Push( name );
2729 
2730     Write ( "<" );
2731     Write ( name );
2732 
2733     _elementJustOpened = true;
2734     ++_depth;
2735 }
2736 
2737 
PushAttribute(const char * name,const char * value)2738 void XMLPrinter::PushAttribute( const char* name, const char* value )
2739 {
2740     TIXMLASSERT( _elementJustOpened );
2741     Putc ( ' ' );
2742     Write( name );
2743     Write( "=\"" );
2744     PrintString( value, false );
2745     Putc ( '\"' );
2746 }
2747 
2748 
PushAttribute(const char * name,int v)2749 void XMLPrinter::PushAttribute( const char* name, int v )
2750 {
2751     char buf[BUF_SIZE];
2752     XMLUtil::ToStr( v, buf, BUF_SIZE );
2753     PushAttribute( name, buf );
2754 }
2755 
2756 
PushAttribute(const char * name,unsigned v)2757 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2758 {
2759     char buf[BUF_SIZE];
2760     XMLUtil::ToStr( v, buf, BUF_SIZE );
2761     PushAttribute( name, buf );
2762 }
2763 
2764 
PushAttribute(const char * name,int64_t v)2765 void XMLPrinter::PushAttribute(const char* name, int64_t v)
2766 {
2767 	char buf[BUF_SIZE];
2768 	XMLUtil::ToStr(v, buf, BUF_SIZE);
2769 	PushAttribute(name, buf);
2770 }
2771 
2772 
PushAttribute(const char * name,uint64_t v)2773 void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2774 {
2775 	char buf[BUF_SIZE];
2776 	XMLUtil::ToStr(v, buf, BUF_SIZE);
2777 	PushAttribute(name, buf);
2778 }
2779 
2780 
PushAttribute(const char * name,bool v)2781 void XMLPrinter::PushAttribute( const char* name, bool v )
2782 {
2783     char buf[BUF_SIZE];
2784     XMLUtil::ToStr( v, buf, BUF_SIZE );
2785     PushAttribute( name, buf );
2786 }
2787 
2788 
PushAttribute(const char * name,double v)2789 void XMLPrinter::PushAttribute( const char* name, double v )
2790 {
2791     char buf[BUF_SIZE];
2792     XMLUtil::ToStr( v, buf, BUF_SIZE );
2793     PushAttribute( name, buf );
2794 }
2795 
2796 
CloseElement(bool compactMode)2797 void XMLPrinter::CloseElement( bool compactMode )
2798 {
2799     --_depth;
2800     const char* name = _stack.Pop();
2801 
2802     if ( _elementJustOpened ) {
2803         Write( "/>" );
2804     }
2805     else {
2806         if ( _textDepth < 0 && !compactMode) {
2807             Putc( '\n' );
2808             PrintSpace( _depth );
2809         }
2810         Write ( "</" );
2811         Write ( name );
2812         Write ( ">" );
2813     }
2814 
2815     if ( _textDepth == _depth ) {
2816         _textDepth = -1;
2817     }
2818     if ( _depth == 0 && !compactMode) {
2819         Putc( '\n' );
2820     }
2821     _elementJustOpened = false;
2822 }
2823 
2824 
SealElementIfJustOpened()2825 void XMLPrinter::SealElementIfJustOpened()
2826 {
2827     if ( !_elementJustOpened ) {
2828         return;
2829     }
2830     _elementJustOpened = false;
2831     Putc( '>' );
2832 }
2833 
2834 
PushText(const char * text,bool cdata)2835 void XMLPrinter::PushText( const char* text, bool cdata )
2836 {
2837     _textDepth = _depth-1;
2838 
2839     SealElementIfJustOpened();
2840     if ( cdata ) {
2841         Write( "<![CDATA[" );
2842         Write( text );
2843         Write( "]]>" );
2844     }
2845     else {
2846         PrintString( text, true );
2847     }
2848 }
2849 
2850 
PushText(int64_t value)2851 void XMLPrinter::PushText( int64_t value )
2852 {
2853     char buf[BUF_SIZE];
2854     XMLUtil::ToStr( value, buf, BUF_SIZE );
2855     PushText( buf, false );
2856 }
2857 
2858 
PushText(uint64_t value)2859 void XMLPrinter::PushText( uint64_t value )
2860 {
2861 	char buf[BUF_SIZE];
2862 	XMLUtil::ToStr(value, buf, BUF_SIZE);
2863 	PushText(buf, false);
2864 }
2865 
2866 
PushText(int value)2867 void XMLPrinter::PushText( int value )
2868 {
2869     char buf[BUF_SIZE];
2870     XMLUtil::ToStr( value, buf, BUF_SIZE );
2871     PushText( buf, false );
2872 }
2873 
2874 
PushText(unsigned value)2875 void XMLPrinter::PushText( unsigned value )
2876 {
2877     char buf[BUF_SIZE];
2878     XMLUtil::ToStr( value, buf, BUF_SIZE );
2879     PushText( buf, false );
2880 }
2881 
2882 
PushText(bool value)2883 void XMLPrinter::PushText( bool value )
2884 {
2885     char buf[BUF_SIZE];
2886     XMLUtil::ToStr( value, buf, BUF_SIZE );
2887     PushText( buf, false );
2888 }
2889 
2890 
PushText(float value)2891 void XMLPrinter::PushText( float value )
2892 {
2893     char buf[BUF_SIZE];
2894     XMLUtil::ToStr( value, buf, BUF_SIZE );
2895     PushText( buf, false );
2896 }
2897 
2898 
PushText(double value)2899 void XMLPrinter::PushText( double value )
2900 {
2901     char buf[BUF_SIZE];
2902     XMLUtil::ToStr( value, buf, BUF_SIZE );
2903     PushText( buf, false );
2904 }
2905 
2906 
PushComment(const char * comment)2907 void XMLPrinter::PushComment( const char* comment )
2908 {
2909     PrepareForNewNode( _compactMode );
2910 
2911     Write( "<!--" );
2912     Write( comment );
2913     Write( "-->" );
2914 }
2915 
2916 
PushDeclaration(const char * value)2917 void XMLPrinter::PushDeclaration( const char* value )
2918 {
2919     PrepareForNewNode( _compactMode );
2920 
2921     Write( "<?" );
2922     Write( value );
2923     Write( "?>" );
2924 }
2925 
2926 
PushUnknown(const char * value)2927 void XMLPrinter::PushUnknown( const char* value )
2928 {
2929     PrepareForNewNode( _compactMode );
2930 
2931     Write( "<!" );
2932     Write( value );
2933     Putc( '>' );
2934 }
2935 
2936 
VisitEnter(const XMLDocument & doc)2937 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2938 {
2939     _processEntities = doc.ProcessEntities();
2940     if ( doc.HasBOM() ) {
2941         PushHeader( true, false );
2942     }
2943     return true;
2944 }
2945 
2946 
VisitEnter(const XMLElement & element,const XMLAttribute * attribute)2947 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2948 {
2949     const XMLElement* parentElem = 0;
2950     if ( element.Parent() ) {
2951         parentElem = element.Parent()->ToElement();
2952     }
2953     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2954     OpenElement( element.Name(), compactMode );
2955     while ( attribute ) {
2956         PushAttribute( attribute->Name(), attribute->Value() );
2957         attribute = attribute->Next();
2958     }
2959     return true;
2960 }
2961 
2962 
VisitExit(const XMLElement & element)2963 bool XMLPrinter::VisitExit( const XMLElement& element )
2964 {
2965     CloseElement( CompactMode(element) );
2966     return true;
2967 }
2968 
2969 
Visit(const XMLText & text)2970 bool XMLPrinter::Visit( const XMLText& text )
2971 {
2972     PushText( text.Value(), text.CData() );
2973     return true;
2974 }
2975 
2976 
Visit(const XMLComment & comment)2977 bool XMLPrinter::Visit( const XMLComment& comment )
2978 {
2979     PushComment( comment.Value() );
2980     return true;
2981 }
2982 
Visit(const XMLDeclaration & declaration)2983 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2984 {
2985     PushDeclaration( declaration.Value() );
2986     return true;
2987 }
2988 
2989 
Visit(const XMLUnknown & unknown)2990 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2991 {
2992     PushUnknown( unknown.Value() );
2993     return true;
2994 }
2995 
2996 }   // namespace tinyxml2
2997