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