e53ac5691c6b9a360993f76568fec8457bd46982
[alexxy/gromacs.git] / src / external / tinyxml2 / tinyxml2.cpp
1 /*
2 Original code by Lee Thomason (www.grinninglizard.com)
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any
6 damages arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any
9 purpose, including commercial applications, and to alter it and
10 redistribute it freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
16
17 2. Altered source versions must be plainly marked as such, and
18 must not be misrepresented as being the original software.
19
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23
24 #include "tinyxml2.h"
25
26 #include <new>          // yes, this one new style header, is in the Android SDK.
27 #if defined(ANDROID_NDK) || defined(__QNXNTO__)
28 #   include <stddef.h>
29 #else
30 #   include <cstddef>
31 #endif
32
33 #if defined(__GNUC__) && __GNUC__>=7
34 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
35 #endif
36
37 static const char LINE_FEED                             = (char)0x0a;                   // all line endings are normalized to LF
38 static const char LF = LINE_FEED;
39 static const char CARRIAGE_RETURN               = (char)0x0d;                   // CR gets filtered out
40 static const char CR = CARRIAGE_RETURN;
41 static const char SINGLE_QUOTE                  = '\'';
42 static const char DOUBLE_QUOTE                  = '\"';
43
44 // Bunch of unicode info at:
45 //              http://www.unicode.org/faq/utf_bom.html
46 //      ef bb bf (Microsoft "lead bytes") - designates UTF-8
47
48 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
49 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
50 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
51
52 namespace tinyxml2
53 {
54
55 struct Entity {
56     const char* pattern;
57     int length;
58     char value;
59 };
60
61 static const int NUM_ENTITIES = 5;
62 static const Entity entities[NUM_ENTITIES] = {
63     { "quot", 4,        DOUBLE_QUOTE },
64     { "amp", 3,         '&'  },
65     { "apos", 4,        SINGLE_QUOTE },
66     { "lt",     2,              '<'      },
67     { "gt",     2,              '>'      }
68 };
69
70
71 StrPair::~StrPair()
72 {
73     Reset();
74 }
75
76
77 void StrPair::TransferTo( StrPair* other )
78 {
79     if ( this == other ) {
80         return;
81     }
82     // This in effect implements the assignment operator by "moving"
83     // ownership (as in auto_ptr).
84
85     TIXMLASSERT( other->_flags == 0 );
86     TIXMLASSERT( other->_start == 0 );
87     TIXMLASSERT( other->_end == 0 );
88
89     other->Reset();
90
91     other->_flags = _flags;
92     other->_start = _start;
93     other->_end = _end;
94
95     _flags = 0;
96     _start = 0;
97     _end = 0;
98 }
99
100 void StrPair::Reset()
101 {
102     if ( _flags & NEEDS_DELETE ) {
103         delete [] _start;
104     }
105     _flags = 0;
106     _start = 0;
107     _end = 0;
108 }
109
110
111 void StrPair::SetStr( const char* str, int flags )
112 {
113     Reset();
114     size_t len = strlen( str );
115     _start = new char[ len+1 ];
116     memcpy( _start, str, len+1 );
117     _end = _start + len;
118     _flags = flags | NEEDS_DELETE;
119 }
120
121
122 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
123 {
124     TIXMLASSERT( endTag && *endTag );
125
126     char* start = p;
127     char  endChar = *endTag;
128     size_t length = strlen( endTag );
129
130     // Inner loop of text parsing.
131     while ( *p ) {
132         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
133             Set( start, p, strFlags );
134             return p + length;
135         }
136         ++p;
137     }
138     return 0;
139 }
140
141
142 char* StrPair::ParseName( char* p )
143 {
144     if ( !p || !(*p) ) {
145         return 0;
146     }
147     if ( !XMLUtil::IsNameStartChar( *p ) ) {
148         return 0;
149     }
150
151     char* const start = p;
152     ++p;
153     while ( *p && XMLUtil::IsNameChar( *p ) ) {
154         ++p;
155     }
156
157     Set( start, p, 0 );
158     return p;
159 }
160
161
162 void StrPair::CollapseWhitespace()
163 {
164     // Adjusting _start would cause undefined behavior on delete[]
165     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
166     // Trim leading space.
167     _start = XMLUtil::SkipWhiteSpace( _start );
168
169     if ( *_start ) {
170         char* p = _start;       // the read pointer
171         char* q = _start;       // the write pointer
172
173         while( *p ) {
174             if ( XMLUtil::IsWhiteSpace( *p )) {
175                 p = XMLUtil::SkipWhiteSpace( p );
176                 if ( *p == 0 ) {
177                     break;    // don't write to q; this trims the trailing space.
178                 }
179                 *q = ' ';
180                 ++q;
181             }
182             *q = *p;
183             ++q;
184             ++p;
185         }
186         *q = 0;
187     }
188 }
189
190
191 const char* StrPair::GetStr()
192 {
193     TIXMLASSERT( _start );
194     TIXMLASSERT( _end );
195     if ( _flags & NEEDS_FLUSH ) {
196         *_end = 0;
197         _flags ^= NEEDS_FLUSH;
198
199         if ( _flags ) {
200             char* p = _start;   // the read pointer
201             char* q = _start;   // the write pointer
202
203             while( p < _end ) {
204                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
205                     // CR-LF pair becomes LF
206                     // CR alone becomes LF
207                     // LF-CR becomes LF
208                     if ( *(p+1) == LF ) {
209                         p += 2;
210                     }
211                     else {
212                         ++p;
213                     }
214                     *q++ = LF;
215                 }
216                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
217                     if ( *(p+1) == CR ) {
218                         p += 2;
219                     }
220                     else {
221                         ++p;
222                     }
223                     *q++ = LF;
224                 }
225                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
226                     // Entities handled by tinyXML2:
227                     // - special entities in the entity table [in/out]
228                     // - numeric character reference [in]
229                     //   &#20013; or &#x4e2d;
230
231                     if ( *(p+1) == '#' ) {
232                         const int buflen = 10;
233                         char buf[buflen] = { 0 };
234                         int len = 0;
235                         char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
236                         if ( adjusted == 0 ) {
237                             *q = *p;
238                             ++p;
239                             ++q;
240                         }
241                         else {
242                             TIXMLASSERT( 0 <= len && len <= buflen );
243                             TIXMLASSERT( q + len <= adjusted );
244                             p = adjusted;
245                             memcpy( q, buf, len );
246                             q += len;
247                         }
248                     }
249                     else {
250                         int i=0;
251                         for(; i<NUM_ENTITIES; ++i ) {
252                             const Entity& entity = entities[i];
253                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
254                                     && *( p + entity.length + 1 ) == ';' ) {
255                                 // Found an entity - convert.
256                                 *q = entity.value;
257                                 ++q;
258                                 p += entity.length + 2;
259                                 break;
260                             }
261                         }
262                         if ( i == NUM_ENTITIES ) {
263                             // fixme: treat as error?
264                             ++p;
265                             ++q;
266                         }
267                     }
268                 }
269                 else {
270                     *q = *p;
271                     ++p;
272                     ++q;
273                 }
274             }
275             *q = 0;
276         }
277         // The loop below has plenty going on, and this
278         // is a less useful mode. Break it out.
279         if ( _flags & COLLAPSE_WHITESPACE ) {
280             CollapseWhitespace();
281         }
282         _flags = (_flags & NEEDS_DELETE);
283     }
284     TIXMLASSERT( _start );
285     return _start;
286 }
287
288
289
290
291 // --------- XMLUtil ----------- //
292
293 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
294 {
295     TIXMLASSERT( p );
296     TIXMLASSERT( bom );
297     *bom = false;
298     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
299     // Check for BOM:
300     if (    *(pu+0) == TIXML_UTF_LEAD_0
301             && *(pu+1) == TIXML_UTF_LEAD_1
302             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
303         *bom = true;
304         p += 3;
305     }
306     TIXMLASSERT( p );
307     return p;
308 }
309
310
311 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
312 {
313     const unsigned long BYTE_MASK = 0xBF;
314     const unsigned long BYTE_MARK = 0x80;
315     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
316
317     if (input < 0x80) {
318         *length = 1;
319     }
320     else if ( input < 0x800 ) {
321         *length = 2;
322     }
323     else if ( input < 0x10000 ) {
324         *length = 3;
325     }
326     else if ( input < 0x200000 ) {
327         *length = 4;
328     }
329     else {
330         *length = 0;    // This code won't covert this correctly anyway.
331         return;
332     }
333
334     output += *length;
335
336     // Scary scary fall throughs.
337     switch (*length) {
338         case 4:
339             --output;
340             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
341             input >>= 6;
342         case 3:
343             --output;
344             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
345             input >>= 6;
346         case 2:
347             --output;
348             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
349             input >>= 6;
350         case 1:
351             --output;
352             *output = (char)(input | FIRST_BYTE_MARK[*length]);
353             break;
354         default:
355             TIXMLASSERT( false );
356     }
357 }
358
359
360 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
361 {
362     // Presume an entity, and pull it out.
363     *length = 0;
364
365     if ( *(p+1) == '#' && *(p+2) ) {
366         unsigned long ucs = 0;
367         TIXMLASSERT( sizeof( ucs ) >= 4 );
368         ptrdiff_t delta = 0;
369         unsigned mult = 1;
370         static const char SEMICOLON = ';';
371
372         if ( *(p+2) == 'x' ) {
373             // Hexadecimal.
374             const char* q = p+3;
375             if ( !(*q) ) {
376                 return 0;
377             }
378
379             q = strchr( q, SEMICOLON );
380
381             if ( !q ) {
382                 return 0;
383             }
384             TIXMLASSERT( *q == SEMICOLON );
385
386             delta = q-p;
387             --q;
388
389             while ( *q != 'x' ) {
390                 unsigned int digit = 0;
391
392                 if ( *q >= '0' && *q <= '9' ) {
393                     digit = *q - '0';
394                 }
395                 else if ( *q >= 'a' && *q <= 'f' ) {
396                     digit = *q - 'a' + 10;
397                 }
398                 else if ( *q >= 'A' && *q <= 'F' ) {
399                     digit = *q - 'A' + 10;
400                 }
401                 else {
402                     return 0;
403                 }
404                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
405                                 TIXMLASSERT( digit >= 0 && digit < 16);
406                 const unsigned int digitScaled = mult * digit;
407                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
408                 ucs += digitScaled;
409                 TIXMLASSERT( mult <= UINT_MAX / 16 );
410                 mult *= 16;
411                 --q;
412             }
413         }
414         else {
415             // Decimal.
416             const char* q = p+2;
417             if ( !(*q) ) {
418                 return 0;
419             }
420
421             q = strchr( q, SEMICOLON );
422
423             if ( !q ) {
424                 return 0;
425             }
426             TIXMLASSERT( *q == SEMICOLON );
427
428             delta = q-p;
429             --q;
430
431             while ( *q != '#' ) {
432                 if ( *q >= '0' && *q <= '9' ) {
433                     const unsigned int digit = *q - '0';
434                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
435                     const unsigned int digitScaled = mult * digit;
436                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
437                     ucs += digitScaled;
438                 }
439                 else {
440                     return 0;
441                 }
442                 TIXMLASSERT( mult <= UINT_MAX / 10 );
443                 mult *= 10;
444                 --q;
445             }
446         }
447         // convert the UCS to UTF-8
448         ConvertUTF32ToUTF8( ucs, value, length );
449         return p + delta + 1;
450     }
451     return p+1;
452 }
453
454
455 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
456 {
457     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
458 }
459
460
461 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
462 {
463     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
464 }
465
466
467 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
468 {
469     TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
470 }
471
472 /*
473         ToStr() of a number is a very tricky topic.
474         https://github.com/leethomason/tinyxml2/issues/106
475 */
476 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
477 {
478     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
479 }
480
481
482 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
483 {
484     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
485 }
486
487
488 bool XMLUtil::ToInt( const char* str, int* value )
489 {
490     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
491         return true;
492     }
493     return false;
494 }
495
496 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
497 {
498     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
499         return true;
500     }
501     return false;
502 }
503
504 bool XMLUtil::ToBool( const char* str, bool* value )
505 {
506     int ival = 0;
507     if ( ToInt( str, &ival )) {
508         *value = (ival==0) ? false : true;
509         return true;
510     }
511     if ( StringEqual( str, "true" ) ) {
512         *value = true;
513         return true;
514     }
515     else if ( StringEqual( str, "false" ) ) {
516         *value = false;
517         return true;
518     }
519     return false;
520 }
521
522
523 bool XMLUtil::ToFloat( const char* str, float* value )
524 {
525     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
526         return true;
527     }
528     return false;
529 }
530
531 bool XMLUtil::ToDouble( const char* str, double* value )
532 {
533     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
534         return true;
535     }
536     return false;
537 }
538
539
540 char* XMLDocument::Identify( char* p, XMLNode** node )
541 {
542     TIXMLASSERT( node );
543     TIXMLASSERT( p );
544     char* const start = p;
545     p = XMLUtil::SkipWhiteSpace( p );
546     if( !*p ) {
547         *node = 0;
548         TIXMLASSERT( p );
549         return p;
550     }
551
552     // What is this thing?
553         // These strings define the matching patters:
554     static const char* xmlHeader                = { "<?" };
555     static const char* commentHeader    = { "<!--" };
556     static const char* dtdHeader                = { "<!" };
557     static const char* cdataHeader              = { "<![CDATA[" };
558     static const char* elementHeader    = { "<" };      // and a header for everything else; check last.
559
560     static const int xmlHeaderLen               = 2;
561     static const int commentHeaderLen   = 4;
562     static const int dtdHeaderLen               = 2;
563     static const int cdataHeaderLen             = 9;
564     static const int elementHeaderLen   = 1;
565
566     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );                // use same memory pool
567     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
568     XMLNode* returnNode = 0;
569     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
570         TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
571         returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
572         returnNode->_memPool = &_commentPool;
573         p += xmlHeaderLen;
574     }
575     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
576         TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
577         returnNode = new (_commentPool.Alloc()) XMLComment( this );
578         returnNode->_memPool = &_commentPool;
579         p += commentHeaderLen;
580     }
581     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
582         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
583         XMLText* text = new (_textPool.Alloc()) XMLText( this );
584         returnNode = text;
585         returnNode->_memPool = &_textPool;
586         p += cdataHeaderLen;
587         text->SetCData( true );
588     }
589     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
590         TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
591         returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
592         returnNode->_memPool = &_commentPool;
593         p += dtdHeaderLen;
594     }
595     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
596         TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
597         returnNode = new (_elementPool.Alloc()) XMLElement( this );
598         returnNode->_memPool = &_elementPool;
599         p += elementHeaderLen;
600     }
601     else {
602         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
603         returnNode = new (_textPool.Alloc()) XMLText( this );
604         returnNode->_memPool = &_textPool;
605         p = start;      // Back it up, all the text counts.
606     }
607
608     TIXMLASSERT( returnNode );
609     TIXMLASSERT( p );
610     *node = returnNode;
611     return p;
612 }
613
614
615 bool XMLDocument::Accept( XMLVisitor* visitor ) const
616 {
617     TIXMLASSERT( visitor );
618     if ( visitor->VisitEnter( *this ) ) {
619         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
620             if ( !node->Accept( visitor ) ) {
621                 break;
622             }
623         }
624     }
625     return visitor->VisitExit( *this );
626 }
627
628
629 // --------- XMLNode ----------- //
630
631 XMLNode::XMLNode( XMLDocument* doc ) :
632     _document( doc ),
633     _parent( 0 ),
634     _firstChild( 0 ), _lastChild( 0 ),
635     _prev( 0 ), _next( 0 ),
636     _memPool( 0 )
637 {
638 }
639
640
641 XMLNode::~XMLNode()
642 {
643     DeleteChildren();
644     if ( _parent ) {
645         _parent->Unlink( this );
646     }
647 }
648
649 const char* XMLNode::Value() const 
650 {
651     return _value.GetStr();
652 }
653
654 void XMLNode::SetValue( const char* str, bool staticMem )
655 {
656     if ( staticMem ) {
657         _value.SetInternedStr( str );
658     }
659     else {
660         _value.SetStr( str );
661     }
662 }
663
664
665 void XMLNode::DeleteChildren()
666 {
667     while( _firstChild ) {
668         TIXMLASSERT( _firstChild->_document == _document );
669         XMLNode* node = _firstChild;
670         Unlink( node );
671
672         DeleteNode( node );
673     }
674     _firstChild = _lastChild = 0;
675 }
676
677
678 void XMLNode::Unlink( XMLNode* child )
679 {
680     TIXMLASSERT( child );
681     TIXMLASSERT( child->_document == _document );
682     if ( child == _firstChild ) {
683         _firstChild = _firstChild->_next;
684     }
685     if ( child == _lastChild ) {
686         _lastChild = _lastChild->_prev;
687     }
688
689     if ( child->_prev ) {
690         child->_prev->_next = child->_next;
691     }
692     if ( child->_next ) {
693         child->_next->_prev = child->_prev;
694     }
695         child->_parent = 0;
696 }
697
698
699 void XMLNode::DeleteChild( XMLNode* node )
700 {
701     TIXMLASSERT( node );
702     TIXMLASSERT( node->_document == _document );
703     TIXMLASSERT( node->_parent == this );
704     DeleteNode( node );
705 }
706
707
708 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
709 {
710     TIXMLASSERT( addThis );
711     if ( addThis->_document != _document ) {
712         TIXMLASSERT( false );
713         return 0;
714     }
715     InsertChildPreamble( addThis );
716
717     if ( _lastChild ) {
718         TIXMLASSERT( _firstChild );
719         TIXMLASSERT( _lastChild->_next == 0 );
720         _lastChild->_next = addThis;
721         addThis->_prev = _lastChild;
722         _lastChild = addThis;
723
724         addThis->_next = 0;
725     }
726     else {
727         TIXMLASSERT( _firstChild == 0 );
728         _firstChild = _lastChild = addThis;
729
730         addThis->_prev = 0;
731         addThis->_next = 0;
732     }
733     addThis->_parent = this;
734     return addThis;
735 }
736
737
738 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
739 {
740     TIXMLASSERT( addThis );
741     if ( addThis->_document != _document ) {
742         TIXMLASSERT( false );
743         return 0;
744     }
745     InsertChildPreamble( addThis );
746
747     if ( _firstChild ) {
748         TIXMLASSERT( _lastChild );
749         TIXMLASSERT( _firstChild->_prev == 0 );
750
751         _firstChild->_prev = addThis;
752         addThis->_next = _firstChild;
753         _firstChild = addThis;
754
755         addThis->_prev = 0;
756     }
757     else {
758         TIXMLASSERT( _lastChild == 0 );
759         _firstChild = _lastChild = addThis;
760
761         addThis->_prev = 0;
762         addThis->_next = 0;
763     }
764     addThis->_parent = this;
765     return addThis;
766 }
767
768
769 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
770 {
771     TIXMLASSERT( addThis );
772     if ( addThis->_document != _document ) {
773         TIXMLASSERT( false );
774         return 0;
775     }
776
777     TIXMLASSERT( afterThis );
778
779     if ( afterThis->_parent != this ) {
780         TIXMLASSERT( false );
781         return 0;
782     }
783
784     if ( afterThis->_next == 0 ) {
785         // The last node or the only node.
786         return InsertEndChild( addThis );
787     }
788     InsertChildPreamble( addThis );
789     addThis->_prev = afterThis;
790     addThis->_next = afterThis->_next;
791     afterThis->_next->_prev = addThis;
792     afterThis->_next = addThis;
793     addThis->_parent = this;
794     return addThis;
795 }
796
797
798
799
800 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
801 {
802     for( XMLNode* node=_firstChild; node; node=node->_next ) {
803         XMLElement* element = node->ToElement();
804         if ( element ) {
805             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
806                 return element;
807             }
808         }
809     }
810     return 0;
811 }
812
813
814 const XMLElement* XMLNode::LastChildElement( const char* value ) const
815 {
816     for( XMLNode* node=_lastChild; node; node=node->_prev ) {
817         XMLElement* element = node->ToElement();
818         if ( element ) {
819             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
820                 return element;
821             }
822         }
823     }
824     return 0;
825 }
826
827
828 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
829 {
830     for( XMLNode* node=this->_next; node; node = node->_next ) {
831         const XMLElement* element = node->ToElement();
832         if ( element
833                 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
834             return element;
835         }
836     }
837     return 0;
838 }
839
840
841 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
842 {
843     for( XMLNode* node=_prev; node; node = node->_prev ) {
844         const XMLElement* element = node->ToElement();
845         if ( element
846                 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
847             return element;
848         }
849     }
850     return 0;
851 }
852
853
854 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
855 {
856     // This is a recursive method, but thinking about it "at the current level"
857     // it is a pretty simple flat list:
858     //          <foo/>
859     //          <!-- comment -->
860     //
861     // With a special case:
862     //          <foo>
863     //          </foo>
864     //          <!-- comment -->
865     //
866     // Where the closing element (/foo) *must* be the next thing after the opening
867     // element, and the names must match. BUT the tricky bit is that the closing
868     // element will be read by the child.
869     //
870     // 'endTag' is the end tag for this node, it is returned by a call to a child.
871     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
872
873     while( p && *p ) {
874         XMLNode* node = 0;
875
876         p = _document->Identify( p, &node );
877         if ( node == 0 ) {
878             break;
879         }
880
881         StrPair endTag;
882         p = node->ParseDeep( p, &endTag );
883         if ( !p ) {
884             DeleteNode( node );
885             if ( !_document->Error() ) {
886                 _document->SetError( XML_ERROR_PARSING, 0, 0 );
887             }
888             break;
889         }
890
891         XMLElement* ele = node->ToElement();
892         if ( ele ) {
893             // We read the end tag. Return it to the parent.
894             if ( ele->ClosingType() == XMLElement::CLOSING ) {
895                 if ( parentEnd ) {
896                     ele->_value.TransferTo( parentEnd );
897                 }
898                 node->_memPool->SetTracked();   // created and then immediately deleted.
899                 DeleteNode( node );
900                 return p;
901             }
902
903             // Handle an end tag returned to this level.
904             // And handle a bunch of annoying errors.
905             bool mismatch = false;
906             if ( endTag.Empty() ) {
907                 if ( ele->ClosingType() == XMLElement::OPEN ) {
908                     mismatch = true;
909                 }
910             }
911             else {
912                 if ( ele->ClosingType() != XMLElement::OPEN ) {
913                     mismatch = true;
914                 }
915                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
916                     mismatch = true;
917                 }
918             }
919             if ( mismatch ) {
920                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
921                 DeleteNode( node );
922                 break;
923             }
924         }
925         InsertEndChild( node );
926     }
927     return 0;
928 }
929
930 void XMLNode::DeleteNode( XMLNode* node )
931 {
932     if ( node == 0 ) {
933         return;
934     }
935     MemPool* pool = node->_memPool;
936     node->~XMLNode();
937     pool->Free( node );
938 }
939
940 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
941 {
942     TIXMLASSERT( insertThis );
943     TIXMLASSERT( insertThis->_document == _document );
944
945     if ( insertThis->_parent )
946         insertThis->_parent->Unlink( insertThis );
947     else
948         insertThis->_memPool->SetTracked();
949 }
950
951 // --------- XMLText ---------- //
952 char* XMLText::ParseDeep( char* p, StrPair* )
953 {
954     const char* start = p;
955     if ( this->CData() ) {
956         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
957         if ( !p ) {
958             _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
959         }
960         return p;
961     }
962     else {
963         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
964         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
965             flags |= StrPair::COLLAPSE_WHITESPACE;
966         }
967
968         p = _value.ParseText( p, "<", flags );
969         if ( p && *p ) {
970             return p-1;
971         }
972         if ( !p ) {
973             _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
974         }
975     }
976     return 0;
977 }
978
979
980 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
981 {
982     if ( !doc ) {
983         doc = _document;
984     }
985     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
986     text->SetCData( this->CData() );
987     return text;
988 }
989
990
991 bool XMLText::ShallowEqual( const XMLNode* compare ) const
992 {
993     const XMLText* text = compare->ToText();
994     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
995 }
996
997
998 bool XMLText::Accept( XMLVisitor* visitor ) const
999 {
1000     TIXMLASSERT( visitor );
1001     return visitor->Visit( *this );
1002 }
1003
1004
1005 // --------- XMLComment ---------- //
1006
1007 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1008 {
1009 }
1010
1011
1012 XMLComment::~XMLComment()
1013 {
1014 }
1015
1016
1017 char* XMLComment::ParseDeep( char* p, StrPair* )
1018 {
1019     // Comment parses as text.
1020     const char* start = p;
1021     p = _value.ParseText( p, "-->", StrPair::COMMENT );
1022     if ( p == 0 ) {
1023         _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
1024     }
1025     return p;
1026 }
1027
1028
1029 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1030 {
1031     if ( !doc ) {
1032         doc = _document;
1033     }
1034     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
1035     return comment;
1036 }
1037
1038
1039 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1040 {
1041     TIXMLASSERT( compare );
1042     const XMLComment* comment = compare->ToComment();
1043     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1044 }
1045
1046
1047 bool XMLComment::Accept( XMLVisitor* visitor ) const
1048 {
1049     TIXMLASSERT( visitor );
1050     return visitor->Visit( *this );
1051 }
1052
1053
1054 // --------- XMLDeclaration ---------- //
1055
1056 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1057 {
1058 }
1059
1060
1061 XMLDeclaration::~XMLDeclaration()
1062 {
1063     //printf( "~XMLDeclaration\n" );
1064 }
1065
1066
1067 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
1068 {
1069     // Declaration parses as text.
1070     const char* start = p;
1071     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1072     if ( p == 0 ) {
1073         _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
1074     }
1075     return p;
1076 }
1077
1078
1079 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1080 {
1081     if ( !doc ) {
1082         doc = _document;
1083     }
1084     XMLDeclaration* dec = doc->NewDeclaration( Value() );       // fixme: this will always allocate memory. Intern?
1085     return dec;
1086 }
1087
1088
1089 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1090 {
1091     TIXMLASSERT( compare );
1092     const XMLDeclaration* declaration = compare->ToDeclaration();
1093     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1094 }
1095
1096
1097
1098 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1099 {
1100     TIXMLASSERT( visitor );
1101     return visitor->Visit( *this );
1102 }
1103
1104 // --------- XMLUnknown ---------- //
1105
1106 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1107 {
1108 }
1109
1110
1111 XMLUnknown::~XMLUnknown()
1112 {
1113 }
1114
1115
1116 char* XMLUnknown::ParseDeep( char* p, StrPair* )
1117 {
1118     // Unknown parses as text.
1119     const char* start = p;
1120
1121     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1122     if ( !p ) {
1123         _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
1124     }
1125     return p;
1126 }
1127
1128
1129 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1130 {
1131     if ( !doc ) {
1132         doc = _document;
1133     }
1134     XMLUnknown* text = doc->NewUnknown( Value() );      // fixme: this will always allocate memory. Intern?
1135     return text;
1136 }
1137
1138
1139 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1140 {
1141     TIXMLASSERT( compare );
1142     const XMLUnknown* unknown = compare->ToUnknown();
1143     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1144 }
1145
1146
1147 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1148 {
1149     TIXMLASSERT( visitor );
1150     return visitor->Visit( *this );
1151 }
1152
1153 // --------- XMLAttribute ---------- //
1154
1155 const char* XMLAttribute::Name() const 
1156 {
1157     return _name.GetStr();
1158 }
1159
1160 const char* XMLAttribute::Value() const 
1161 {
1162     return _value.GetStr();
1163 }
1164
1165 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
1166 {
1167     // Parse using the name rules: bug fix, was using ParseText before
1168     p = _name.ParseName( p );
1169     if ( !p || !*p ) {
1170         return 0;
1171     }
1172
1173     // Skip white space before =
1174     p = XMLUtil::SkipWhiteSpace( p );
1175     if ( *p != '=' ) {
1176         return 0;
1177     }
1178
1179     ++p;        // move up to opening quote
1180     p = XMLUtil::SkipWhiteSpace( p );
1181     if ( *p != '\"' && *p != '\'' ) {
1182         return 0;
1183     }
1184
1185     char endTag[2] = { *p, 0 };
1186     ++p;        // move past opening quote
1187
1188     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1189     return p;
1190 }
1191
1192
1193 void XMLAttribute::SetName( const char* n )
1194 {
1195     _name.SetStr( n );
1196 }
1197
1198
1199 XMLError XMLAttribute::QueryIntValue( int* value ) const
1200 {
1201     if ( XMLUtil::ToInt( Value(), value )) {
1202         return XML_NO_ERROR;
1203     }
1204     return XML_WRONG_ATTRIBUTE_TYPE;
1205 }
1206
1207
1208 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1209 {
1210     if ( XMLUtil::ToUnsigned( Value(), value )) {
1211         return XML_NO_ERROR;
1212     }
1213     return XML_WRONG_ATTRIBUTE_TYPE;
1214 }
1215
1216
1217 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1218 {
1219     if ( XMLUtil::ToBool( Value(), value )) {
1220         return XML_NO_ERROR;
1221     }
1222     return XML_WRONG_ATTRIBUTE_TYPE;
1223 }
1224
1225
1226 XMLError XMLAttribute::QueryFloatValue( float* value ) const
1227 {
1228     if ( XMLUtil::ToFloat( Value(), value )) {
1229         return XML_NO_ERROR;
1230     }
1231     return XML_WRONG_ATTRIBUTE_TYPE;
1232 }
1233
1234
1235 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1236 {
1237     if ( XMLUtil::ToDouble( Value(), value )) {
1238         return XML_NO_ERROR;
1239     }
1240     return XML_WRONG_ATTRIBUTE_TYPE;
1241 }
1242
1243
1244 void XMLAttribute::SetAttribute( const char* v )
1245 {
1246     _value.SetStr( v );
1247 }
1248
1249
1250 void XMLAttribute::SetAttribute( int v )
1251 {
1252     char buf[BUF_SIZE];
1253     XMLUtil::ToStr( v, buf, BUF_SIZE );
1254     _value.SetStr( buf );
1255 }
1256
1257
1258 void XMLAttribute::SetAttribute( unsigned v )
1259 {
1260     char buf[BUF_SIZE];
1261     XMLUtil::ToStr( v, buf, BUF_SIZE );
1262     _value.SetStr( buf );
1263 }
1264
1265
1266 void XMLAttribute::SetAttribute( bool v )
1267 {
1268     char buf[BUF_SIZE];
1269     XMLUtil::ToStr( v, buf, BUF_SIZE );
1270     _value.SetStr( buf );
1271 }
1272
1273 void XMLAttribute::SetAttribute( double v )
1274 {
1275     char buf[BUF_SIZE];
1276     XMLUtil::ToStr( v, buf, BUF_SIZE );
1277     _value.SetStr( buf );
1278 }
1279
1280 void XMLAttribute::SetAttribute( float v )
1281 {
1282     char buf[BUF_SIZE];
1283     XMLUtil::ToStr( v, buf, BUF_SIZE );
1284     _value.SetStr( buf );
1285 }
1286
1287
1288 // --------- XMLElement ---------- //
1289 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1290     _closingType( 0 ),
1291     _rootAttribute( 0 )
1292 {
1293 }
1294
1295
1296 XMLElement::~XMLElement()
1297 {
1298     while( _rootAttribute ) {
1299         XMLAttribute* next = _rootAttribute->_next;
1300         DeleteAttribute( _rootAttribute );
1301         _rootAttribute = next;
1302     }
1303 }
1304
1305
1306 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1307 {
1308     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1309         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1310             return a;
1311         }
1312     }
1313     return 0;
1314 }
1315
1316
1317 const char* XMLElement::Attribute( const char* name, const char* value ) const
1318 {
1319     const XMLAttribute* a = FindAttribute( name );
1320     if ( !a ) {
1321         return 0;
1322     }
1323     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1324         return a->Value();
1325     }
1326     return 0;
1327 }
1328
1329
1330 const char* XMLElement::GetText() const
1331 {
1332     if ( FirstChild() && FirstChild()->ToText() ) {
1333         return FirstChild()->Value();
1334     }
1335     return 0;
1336 }
1337
1338
1339 void    XMLElement::SetText( const char* inText )
1340 {
1341         if ( FirstChild() && FirstChild()->ToText() )
1342                 FirstChild()->SetValue( inText );
1343         else {
1344                 XMLText*        theText = GetDocument()->NewText( inText );
1345                 InsertFirstChild( theText );
1346         }
1347 }
1348
1349
1350 void XMLElement::SetText( int v ) 
1351 {
1352     char buf[BUF_SIZE];
1353     XMLUtil::ToStr( v, buf, BUF_SIZE );
1354     SetText( buf );
1355 }
1356
1357
1358 void XMLElement::SetText( unsigned v ) 
1359 {
1360     char buf[BUF_SIZE];
1361     XMLUtil::ToStr( v, buf, BUF_SIZE );
1362     SetText( buf );
1363 }
1364
1365
1366 void XMLElement::SetText( bool v ) 
1367 {
1368     char buf[BUF_SIZE];
1369     XMLUtil::ToStr( v, buf, BUF_SIZE );
1370     SetText( buf );
1371 }
1372
1373
1374 void XMLElement::SetText( float v ) 
1375 {
1376     char buf[BUF_SIZE];
1377     XMLUtil::ToStr( v, buf, BUF_SIZE );
1378     SetText( buf );
1379 }
1380
1381
1382 void XMLElement::SetText( double v ) 
1383 {
1384     char buf[BUF_SIZE];
1385     XMLUtil::ToStr( v, buf, BUF_SIZE );
1386     SetText( buf );
1387 }
1388
1389
1390 XMLError XMLElement::QueryIntText( int* ival ) const
1391 {
1392     if ( FirstChild() && FirstChild()->ToText() ) {
1393         const char* t = FirstChild()->Value();
1394         if ( XMLUtil::ToInt( t, ival ) ) {
1395             return XML_SUCCESS;
1396         }
1397         return XML_CAN_NOT_CONVERT_TEXT;
1398     }
1399     return XML_NO_TEXT_NODE;
1400 }
1401
1402
1403 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1404 {
1405     if ( FirstChild() && FirstChild()->ToText() ) {
1406         const char* t = FirstChild()->Value();
1407         if ( XMLUtil::ToUnsigned( t, uval ) ) {
1408             return XML_SUCCESS;
1409         }
1410         return XML_CAN_NOT_CONVERT_TEXT;
1411     }
1412     return XML_NO_TEXT_NODE;
1413 }
1414
1415
1416 XMLError XMLElement::QueryBoolText( bool* bval ) const
1417 {
1418     if ( FirstChild() && FirstChild()->ToText() ) {
1419         const char* t = FirstChild()->Value();
1420         if ( XMLUtil::ToBool( t, bval ) ) {
1421             return XML_SUCCESS;
1422         }
1423         return XML_CAN_NOT_CONVERT_TEXT;
1424     }
1425     return XML_NO_TEXT_NODE;
1426 }
1427
1428
1429 XMLError XMLElement::QueryDoubleText( double* dval ) const
1430 {
1431     if ( FirstChild() && FirstChild()->ToText() ) {
1432         const char* t = FirstChild()->Value();
1433         if ( XMLUtil::ToDouble( t, dval ) ) {
1434             return XML_SUCCESS;
1435         }
1436         return XML_CAN_NOT_CONVERT_TEXT;
1437     }
1438     return XML_NO_TEXT_NODE;
1439 }
1440
1441
1442 XMLError XMLElement::QueryFloatText( float* fval ) const
1443 {
1444     if ( FirstChild() && FirstChild()->ToText() ) {
1445         const char* t = FirstChild()->Value();
1446         if ( XMLUtil::ToFloat( t, fval ) ) {
1447             return XML_SUCCESS;
1448         }
1449         return XML_CAN_NOT_CONVERT_TEXT;
1450     }
1451     return XML_NO_TEXT_NODE;
1452 }
1453
1454
1455
1456 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1457 {
1458     XMLAttribute* last = 0;
1459     XMLAttribute* attrib = 0;
1460     for( attrib = _rootAttribute;
1461             attrib;
1462             last = attrib, attrib = attrib->_next ) {
1463         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1464             break;
1465         }
1466     }
1467     if ( !attrib ) {
1468         TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1469         attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1470         attrib->_memPool = &_document->_attributePool;
1471         if ( last ) {
1472             last->_next = attrib;
1473         }
1474         else {
1475             _rootAttribute = attrib;
1476         }
1477         attrib->SetName( name );
1478         attrib->_memPool->SetTracked(); // always created and linked.
1479     }
1480     return attrib;
1481 }
1482
1483
1484 void XMLElement::DeleteAttribute( const char* name )
1485 {
1486     XMLAttribute* prev = 0;
1487     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1488         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1489             if ( prev ) {
1490                 prev->_next = a->_next;
1491             }
1492             else {
1493                 _rootAttribute = a->_next;
1494             }
1495             DeleteAttribute( a );
1496             break;
1497         }
1498         prev = a;
1499     }
1500 }
1501
1502
1503 char* XMLElement::ParseAttributes( char* p )
1504 {
1505     const char* start = p;
1506     XMLAttribute* prevAttribute = 0;
1507
1508     // Read the attributes.
1509     while( p ) {
1510         p = XMLUtil::SkipWhiteSpace( p );
1511         if ( !(*p) ) {
1512             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
1513             return 0;
1514         }
1515
1516         // attribute.
1517         if (XMLUtil::IsNameStartChar( *p ) ) {
1518             TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1519             XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1520             attrib->_memPool = &_document->_attributePool;
1521                         attrib->_memPool->SetTracked();
1522
1523             p = attrib->ParseDeep( p, _document->ProcessEntities() );
1524             if ( !p || Attribute( attrib->Name() ) ) {
1525                 DeleteAttribute( attrib );
1526                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1527                 return 0;
1528             }
1529             // There is a minor bug here: if the attribute in the source xml
1530             // document is duplicated, it will not be detected and the
1531             // attribute will be doubly added. However, tracking the 'prevAttribute'
1532             // avoids re-scanning the attribute list. Preferring performance for
1533             // now, may reconsider in the future.
1534             if ( prevAttribute ) {
1535                 prevAttribute->_next = attrib;
1536             }
1537             else {
1538                 _rootAttribute = attrib;
1539             }
1540             prevAttribute = attrib;
1541         }
1542         // end of the tag
1543         else if ( *p == '/' && *(p+1) == '>' ) {
1544             _closingType = CLOSED;
1545             return p+2; // done; sealed element.
1546         }
1547         // end of the tag
1548         else if ( *p == '>' ) {
1549             ++p;
1550             break;
1551         }
1552         else {
1553             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1554             return 0;
1555         }
1556     }
1557     return p;
1558 }
1559
1560 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1561 {
1562     if ( attribute == 0 ) {
1563         return;
1564     }
1565     MemPool* pool = attribute->_memPool;
1566     attribute->~XMLAttribute();
1567     pool->Free( attribute );
1568 }
1569
1570 //
1571 //      <ele></ele>
1572 //      <ele>foo<b>bar</b></ele>
1573 //
1574 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
1575 {
1576     // Read the element name.
1577     p = XMLUtil::SkipWhiteSpace( p );
1578
1579     // The closing element is the </element> form. It is
1580     // parsed just like a regular element then deleted from
1581     // the DOM.
1582     if ( *p == '/' ) {
1583         _closingType = CLOSING;
1584         ++p;
1585     }
1586
1587     p = _value.ParseName( p );
1588     if ( _value.Empty() ) {
1589         return 0;
1590     }
1591
1592     p = ParseAttributes( p );
1593     if ( !p || !*p || _closingType ) {
1594         return p;
1595     }
1596
1597     p = XMLNode::ParseDeep( p, strPair );
1598     return p;
1599 }
1600
1601
1602
1603 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1604 {
1605     if ( !doc ) {
1606         doc = _document;
1607     }
1608     XMLElement* element = doc->NewElement( Value() );                                   // fixme: this will always allocate memory. Intern?
1609     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1610         element->SetAttribute( a->Name(), a->Value() );                                 // fixme: this will always allocate memory. Intern?
1611     }
1612     return element;
1613 }
1614
1615
1616 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1617 {
1618     TIXMLASSERT( compare );
1619     const XMLElement* other = compare->ToElement();
1620     if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1621
1622         const XMLAttribute* a=FirstAttribute();
1623         const XMLAttribute* b=other->FirstAttribute();
1624
1625         while ( a && b ) {
1626             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1627                 return false;
1628             }
1629             a = a->Next();
1630             b = b->Next();
1631         }
1632         if ( a || b ) {
1633             // different count
1634             return false;
1635         }
1636         return true;
1637     }
1638     return false;
1639 }
1640
1641
1642 bool XMLElement::Accept( XMLVisitor* visitor ) const
1643 {
1644     TIXMLASSERT( visitor );
1645     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
1646         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1647             if ( !node->Accept( visitor ) ) {
1648                 break;
1649             }
1650         }
1651     }
1652     return visitor->VisitExit( *this );
1653 }
1654
1655
1656 // --------- XMLDocument ----------- //
1657
1658 // Warning: List must match 'enum XMLError'
1659 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1660     "XML_SUCCESS",
1661     "XML_NO_ATTRIBUTE",
1662     "XML_WRONG_ATTRIBUTE_TYPE",
1663     "XML_ERROR_FILE_NOT_FOUND",
1664     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1665     "XML_ERROR_FILE_READ_ERROR",
1666     "XML_ERROR_ELEMENT_MISMATCH",
1667     "XML_ERROR_PARSING_ELEMENT",
1668     "XML_ERROR_PARSING_ATTRIBUTE",
1669     "XML_ERROR_IDENTIFYING_TAG",
1670     "XML_ERROR_PARSING_TEXT",
1671     "XML_ERROR_PARSING_CDATA",
1672     "XML_ERROR_PARSING_COMMENT",
1673     "XML_ERROR_PARSING_DECLARATION",
1674     "XML_ERROR_PARSING_UNKNOWN",
1675     "XML_ERROR_EMPTY_DOCUMENT",
1676     "XML_ERROR_MISMATCHED_ELEMENT",
1677     "XML_ERROR_PARSING",
1678     "XML_CAN_NOT_CONVERT_TEXT",
1679     "XML_NO_TEXT_NODE"
1680 };
1681
1682
1683 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
1684     XMLNode( 0 ),
1685     _writeBOM( false ),
1686     _processEntities( processEntities ),
1687     _errorID( XML_NO_ERROR ),
1688     _whitespace( whitespace ),
1689     _errorStr1( 0 ),
1690     _errorStr2( 0 ),
1691     _charBuffer( 0 )
1692 {
1693     _document = this;   // avoid warning about 'this' in initializer list
1694 }
1695
1696
1697 XMLDocument::~XMLDocument()
1698 {
1699     Clear();
1700 }
1701
1702
1703 void XMLDocument::Clear()
1704 {
1705     DeleteChildren();
1706
1707 #ifdef DEBUG
1708     const bool hadError = Error();
1709 #endif
1710     _errorID = XML_NO_ERROR;
1711     _errorStr1 = 0;
1712     _errorStr2 = 0;
1713
1714     delete [] _charBuffer;
1715     _charBuffer = 0;
1716
1717 #if 0
1718     _textPool.Trace( "text" );
1719     _elementPool.Trace( "element" );
1720     _commentPool.Trace( "comment" );
1721     _attributePool.Trace( "attribute" );
1722 #endif
1723     
1724 #ifdef DEBUG
1725     if ( !hadError ) {
1726         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
1727         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1728         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
1729         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
1730     }
1731 #endif
1732 }
1733
1734
1735 XMLElement* XMLDocument::NewElement( const char* name )
1736 {
1737     TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
1738     XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1739     ele->_memPool = &_elementPool;
1740     ele->SetName( name );
1741     return ele;
1742 }
1743
1744
1745 XMLComment* XMLDocument::NewComment( const char* str )
1746 {
1747     TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
1748     XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1749     comment->_memPool = &_commentPool;
1750     comment->SetValue( str );
1751     return comment;
1752 }
1753
1754
1755 XMLText* XMLDocument::NewText( const char* str )
1756 {
1757     TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
1758     XMLText* text = new (_textPool.Alloc()) XMLText( this );
1759     text->_memPool = &_textPool;
1760     text->SetValue( str );
1761     return text;
1762 }
1763
1764
1765 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1766 {
1767     TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
1768     XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1769     dec->_memPool = &_commentPool;
1770     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1771     return dec;
1772 }
1773
1774
1775 XMLUnknown* XMLDocument::NewUnknown( const char* str )
1776 {
1777     TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
1778     XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1779     unk->_memPool = &_commentPool;
1780     unk->SetValue( str );
1781     return unk;
1782 }
1783
1784 static FILE* callfopen( const char* filepath, const char* mode )
1785 {
1786     TIXMLASSERT( filepath );
1787     TIXMLASSERT( mode );
1788 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1789     FILE* fp = 0;
1790     errno_t err = fopen_s( &fp, filepath, mode );
1791     if ( err ) {
1792         return 0;
1793     }
1794 #else
1795     FILE* fp = fopen( filepath, mode );
1796 #endif
1797     return fp;
1798 }
1799     
1800 void XMLDocument::DeleteNode( XMLNode* node )   {
1801     TIXMLASSERT( node );
1802     TIXMLASSERT(node->_document == this );
1803     if (node->_parent) {
1804         node->_parent->DeleteChild( node );
1805     }
1806     else {
1807         // Isn't in the tree.
1808         // Use the parent delete.
1809         // Also, we need to mark it tracked: we 'know'
1810         // it was never used.
1811         node->_memPool->SetTracked();
1812         // Call the static XMLNode version:
1813         XMLNode::DeleteNode(node);
1814     }
1815 }
1816
1817
1818 XMLError XMLDocument::LoadFile( const char* filename )
1819 {
1820     Clear();
1821     FILE* fp = callfopen( filename, "rb" );
1822     if ( !fp ) {
1823         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1824         return _errorID;
1825     }
1826     LoadFile( fp );
1827     fclose( fp );
1828     return _errorID;
1829 }
1830
1831
1832 XMLError XMLDocument::LoadFile( FILE* fp )
1833 {
1834     Clear();
1835
1836     fseek( fp, 0, SEEK_SET );
1837     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
1838         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1839         return _errorID;
1840     }
1841
1842     fseek( fp, 0, SEEK_END );
1843     const long filelength = ftell( fp );
1844     fseek( fp, 0, SEEK_SET );
1845     if ( filelength == -1L ) {
1846         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1847         return _errorID;
1848     }
1849
1850     const size_t size = filelength;
1851     if ( size == 0 ) {
1852         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1853         return _errorID;
1854     }
1855
1856     _charBuffer = new char[size+1];
1857     size_t read = fread( _charBuffer, 1, size, fp );
1858     if ( read != size ) {
1859         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1860         return _errorID;
1861     }
1862
1863     _charBuffer[size] = 0;
1864
1865     Parse();
1866     return _errorID;
1867 }
1868
1869
1870 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
1871 {
1872     FILE* fp = callfopen( filename, "w" );
1873     if ( !fp ) {
1874         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
1875         return _errorID;
1876     }
1877     SaveFile(fp, compact);
1878     fclose( fp );
1879     return _errorID;
1880 }
1881
1882
1883 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
1884 {
1885     XMLPrinter stream( fp, compact );
1886     Print( &stream );
1887     return _errorID;
1888 }
1889
1890
1891 XMLError XMLDocument::Parse( const char* p, size_t len )
1892 {
1893     Clear();
1894
1895     if ( len == 0 || !p || !*p ) {
1896         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1897         return _errorID;
1898     }
1899     if ( len == (size_t)(-1) ) {
1900         len = strlen( p );
1901     }
1902     _charBuffer = new char[ len+1 ];
1903     memcpy( _charBuffer, p, len );
1904     _charBuffer[len] = 0;
1905
1906     Parse();
1907     if ( Error() ) {
1908         // clean up now essentially dangling memory.
1909         // and the parse fail can put objects in the
1910         // pools that are dead and inaccessible.
1911         DeleteChildren();
1912         _elementPool.Clear();
1913         _attributePool.Clear();
1914         _textPool.Clear();
1915         _commentPool.Clear();
1916     }
1917     return _errorID;
1918 }
1919
1920
1921 void XMLDocument::Print( XMLPrinter* streamer ) const
1922 {
1923     XMLPrinter stdStreamer( stdout );
1924     if ( !streamer ) {
1925         streamer = &stdStreamer;
1926     }
1927     Accept( streamer );
1928 }
1929
1930
1931 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
1932 {
1933     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
1934     _errorID = error;
1935     _errorStr1 = str1;
1936     _errorStr2 = str2;
1937 }
1938
1939 const char* XMLDocument::ErrorName() const
1940 {
1941         TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
1942         return _errorNames[_errorID];
1943 }
1944
1945 void XMLDocument::PrintError() const
1946 {
1947     if ( Error() ) {
1948         static const int LEN = 20;
1949         char buf1[LEN] = { 0 };
1950         char buf2[LEN] = { 0 };
1951
1952         if ( _errorStr1 ) {
1953             TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
1954         }
1955         if ( _errorStr2 ) {
1956             TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
1957         }
1958
1959         printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1960                 _errorID, ErrorName(), buf1, buf2 );
1961     }
1962 }
1963
1964 void XMLDocument::Parse()
1965 {
1966     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1967     TIXMLASSERT( _charBuffer );
1968     char* p = _charBuffer;
1969     p = XMLUtil::SkipWhiteSpace( p );
1970     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
1971     if ( !*p ) {
1972         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1973         return;
1974     }
1975     ParseDeep(p, 0 );
1976 }
1977
1978 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
1979     _elementJustOpened( false ),
1980     _firstElement( true ),
1981     _fp( file ),
1982     _depth( depth ),
1983     _textDepth( -1 ),
1984     _processEntities( true ),
1985     _compactMode( compact )
1986 {
1987     for( int i=0; i<ENTITY_RANGE; ++i ) {
1988         _entityFlag[i] = false;
1989         _restrictedEntityFlag[i] = false;
1990     }
1991     for( int i=0; i<NUM_ENTITIES; ++i ) {
1992         const char entityValue = entities[i].value;
1993         TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1994         _entityFlag[ (unsigned char)entityValue ] = true;
1995     }
1996     _restrictedEntityFlag[(unsigned char)'&'] = true;
1997     _restrictedEntityFlag[(unsigned char)'<'] = true;
1998     _restrictedEntityFlag[(unsigned char)'>'] = true;   // not required, but consistency is nice
1999     _buffer.Push( 0 );
2000 }
2001
2002
2003 void XMLPrinter::Print( const char* format, ... )
2004 {
2005     va_list     va;
2006     va_start( va, format );
2007
2008     if ( _fp ) {
2009         vfprintf( _fp, format, va );
2010     }
2011     else {
2012 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
2013                 #if defined(WINCE)
2014                 int len = 512;
2015                 do {
2016                     len = len*2;
2017                     char* str = new char[len]();
2018                         len = _vsnprintf(str, len, format, va);
2019                         delete[] str;
2020                 }while (len < 0);
2021                 #else
2022         int len = _vscprintf( format, va );
2023                 #endif
2024 #else
2025         int len = vsnprintf( 0, 0, format, va );
2026 #endif
2027         // Close out and re-start the va-args
2028         va_end( va );
2029         va_start( va, format );
2030         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2031         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.
2032 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
2033                 #if defined(WINCE)
2034                 _vsnprintf( p, len+1, format, va );
2035                 #else
2036                 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
2037                 #endif
2038 #else
2039                 vsnprintf( p, len+1, format, va );
2040 #endif
2041     }
2042     va_end( va );
2043 }
2044
2045
2046 void XMLPrinter::PrintSpace( int depth )
2047 {
2048     for( int i=0; i<depth; ++i ) {
2049         Print( "  " );
2050     }
2051 }
2052
2053
2054 void XMLPrinter::PrintString( const char* p, bool restricted )
2055 {
2056     // Look for runs of bytes between entities to print.
2057     const char* q = p;
2058
2059     if ( _processEntities ) {
2060         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2061         while ( *q ) {
2062             // Remember, char is sometimes signed. (How many times has that bitten me?)
2063             if ( *q > 0 && *q < ENTITY_RANGE ) {
2064                 // Check for entities. If one is found, flush
2065                 // the stream up until the entity, write the
2066                 // entity, and keep looking.
2067                 if ( flag[(unsigned char)(*q)] ) {
2068                     while ( p < q ) {
2069                         Print( "%c", *p );
2070                         ++p;
2071                     }
2072                     for( int i=0; i<NUM_ENTITIES; ++i ) {
2073                         if ( entities[i].value == *q ) {
2074                             Print( "&%s;", entities[i].pattern );
2075                             break;
2076                         }
2077                     }
2078                     ++p;
2079                 }
2080             }
2081             ++q;
2082         }
2083     }
2084     // Flush the remaining string. This will be the entire
2085     // string if an entity wasn't found.
2086     if ( !_processEntities || (q-p > 0) ) {
2087         Print( "%s", p );
2088     }
2089 }
2090
2091
2092 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2093 {
2094     if ( writeBOM ) {
2095         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2096         Print( "%s", bom );
2097     }
2098     if ( writeDec ) {
2099         PushDeclaration( "xml version=\"1.0\"" );
2100     }
2101 }
2102
2103
2104 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2105 {
2106     SealElementIfJustOpened();
2107     _stack.Push( name );
2108
2109     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
2110         Print( "\n" );
2111     }
2112     if ( !compactMode ) {
2113         PrintSpace( _depth );
2114     }
2115
2116     Print( "<%s", name );
2117     _elementJustOpened = true;
2118     _firstElement = false;
2119     ++_depth;
2120 }
2121
2122
2123 void XMLPrinter::PushAttribute( const char* name, const char* value )
2124 {
2125     TIXMLASSERT( _elementJustOpened );
2126     Print( " %s=\"", name );
2127     PrintString( value, false );
2128     Print( "\"" );
2129 }
2130
2131
2132 void XMLPrinter::PushAttribute( const char* name, int v )
2133 {
2134     char buf[BUF_SIZE];
2135     XMLUtil::ToStr( v, buf, BUF_SIZE );
2136     PushAttribute( name, buf );
2137 }
2138
2139
2140 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2141 {
2142     char buf[BUF_SIZE];
2143     XMLUtil::ToStr( v, buf, BUF_SIZE );
2144     PushAttribute( name, buf );
2145 }
2146
2147
2148 void XMLPrinter::PushAttribute( const char* name, bool v )
2149 {
2150     char buf[BUF_SIZE];
2151     XMLUtil::ToStr( v, buf, BUF_SIZE );
2152     PushAttribute( name, buf );
2153 }
2154
2155
2156 void XMLPrinter::PushAttribute( const char* name, double v )
2157 {
2158     char buf[BUF_SIZE];
2159     XMLUtil::ToStr( v, buf, BUF_SIZE );
2160     PushAttribute( name, buf );
2161 }
2162
2163
2164 void XMLPrinter::CloseElement( bool compactMode )
2165 {
2166     --_depth;
2167     const char* name = _stack.Pop();
2168
2169     if ( _elementJustOpened ) {
2170         Print( "/>" );
2171     }
2172     else {
2173         if ( _textDepth < 0 && !compactMode) {
2174             Print( "\n" );
2175             PrintSpace( _depth );
2176         }
2177         Print( "</%s>", name );
2178     }
2179
2180     if ( _textDepth == _depth ) {
2181         _textDepth = -1;
2182     }
2183     if ( _depth == 0 && !compactMode) {
2184         Print( "\n" );
2185     }
2186     _elementJustOpened = false;
2187 }
2188
2189
2190 void XMLPrinter::SealElementIfJustOpened()
2191 {
2192     if ( !_elementJustOpened ) {
2193         return;
2194     }
2195     _elementJustOpened = false;
2196     Print( ">" );
2197 }
2198
2199
2200 void XMLPrinter::PushText( const char* text, bool cdata )
2201 {
2202     _textDepth = _depth-1;
2203
2204     SealElementIfJustOpened();
2205     if ( cdata ) {
2206         Print( "<![CDATA[" );
2207         Print( "%s", text );
2208         Print( "]]>" );
2209     }
2210     else {
2211         PrintString( text, true );
2212     }
2213 }
2214
2215 void XMLPrinter::PushText( int value )
2216 {
2217     char buf[BUF_SIZE];
2218     XMLUtil::ToStr( value, buf, BUF_SIZE );
2219     PushText( buf, false );
2220 }
2221
2222
2223 void XMLPrinter::PushText( unsigned value )
2224 {
2225     char buf[BUF_SIZE];
2226     XMLUtil::ToStr( value, buf, BUF_SIZE );
2227     PushText( buf, false );
2228 }
2229
2230
2231 void XMLPrinter::PushText( bool value )
2232 {
2233     char buf[BUF_SIZE];
2234     XMLUtil::ToStr( value, buf, BUF_SIZE );
2235     PushText( buf, false );
2236 }
2237
2238
2239 void XMLPrinter::PushText( float value )
2240 {
2241     char buf[BUF_SIZE];
2242     XMLUtil::ToStr( value, buf, BUF_SIZE );
2243     PushText( buf, false );
2244 }
2245
2246
2247 void XMLPrinter::PushText( double value )
2248 {
2249     char buf[BUF_SIZE];
2250     XMLUtil::ToStr( value, buf, BUF_SIZE );
2251     PushText( buf, false );
2252 }
2253
2254
2255 void XMLPrinter::PushComment( const char* comment )
2256 {
2257     SealElementIfJustOpened();
2258     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2259         Print( "\n" );
2260         PrintSpace( _depth );
2261     }
2262     _firstElement = false;
2263     Print( "<!--%s-->", comment );
2264 }
2265
2266
2267 void XMLPrinter::PushDeclaration( const char* value )
2268 {
2269     SealElementIfJustOpened();
2270     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2271         Print( "\n" );
2272         PrintSpace( _depth );
2273     }
2274     _firstElement = false;
2275     Print( "<?%s?>", value );
2276 }
2277
2278
2279 void XMLPrinter::PushUnknown( const char* value )
2280 {
2281     SealElementIfJustOpened();
2282     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2283         Print( "\n" );
2284         PrintSpace( _depth );
2285     }
2286     _firstElement = false;
2287     Print( "<!%s>", value );
2288 }
2289
2290
2291 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2292 {
2293     _processEntities = doc.ProcessEntities();
2294     if ( doc.HasBOM() ) {
2295         PushHeader( true, false );
2296     }
2297     return true;
2298 }
2299
2300
2301 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2302 {
2303         const XMLElement*       parentElem = element.Parent()->ToElement();
2304         bool            compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2305     OpenElement( element.Name(), compactMode );
2306     while ( attribute ) {
2307         PushAttribute( attribute->Name(), attribute->Value() );
2308         attribute = attribute->Next();
2309     }
2310     return true;
2311 }
2312
2313
2314 bool XMLPrinter::VisitExit( const XMLElement& element )
2315 {
2316     CloseElement( CompactMode(element) );
2317     return true;
2318 }
2319
2320
2321 bool XMLPrinter::Visit( const XMLText& text )
2322 {
2323     PushText( text.Value(), text.CData() );
2324     return true;
2325 }
2326
2327
2328 bool XMLPrinter::Visit( const XMLComment& comment )
2329 {
2330     PushComment( comment.Value() );
2331     return true;
2332 }
2333
2334 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2335 {
2336     PushDeclaration( declaration.Value() );
2337     return true;
2338 }
2339
2340
2341 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2342 {
2343     PushUnknown( unknown.Value() );
2344     return true;
2345 }
2346
2347 }   // namespace tinyxml2
2348