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