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