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