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