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 // 中 or 中
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