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