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 #include "tinyxml2.h"
24 
25 #include <cstdio>
26 #include <cstdlib>
27 #include <new>
28 #include <cstddef>
29 
30 #include <fcntl.h>
31 using namespace tinyxml2;
32 
33 static const char LINE_FEED                = (char)0x0a;            // all line endings are normalized to LF
34 static const char LF = LINE_FEED;
35 static const char CARRIAGE_RETURN        = (char)0x0d;            // CR gets filtered out
36 static const char CR = CARRIAGE_RETURN;
37 static const char SINGLE_QUOTE            = '\'';
38 static const char DOUBLE_QUOTE            = '\"';
39 
40 // Bunch of unicode info at:
41 //        http://www.unicode.org/faq/utf_bom.html
42 //    ef bb bf (Microsoft "lead bytes") - designates UTF-8
43 
44 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
47 
48 
49 #define DELETE_NODE( node )    {            \
50     if ( node ) {                        \
51         MemPool* pool = node->memPool;    \
52         node->~XMLNode();                \
53         pool->Free( node );                \
54     }                                    \
55 }
56 #define DELETE_ATTRIBUTE( attrib ) {        \
57     if ( attrib ) {                            \
58         MemPool* pool = attrib->memPool;    \
59         attrib->~XMLAttribute();            \
60         pool->Free( attrib );                \
61     }                                        \
62 }
63 
64 struct Entity {
65     const char* pattern;
66     int length;
67     char value;
68 };
69 
70 static const int NUM_ENTITIES = 5;
71 static const Entity entities[NUM_ENTITIES] =
72 {
73     { "quot", 4,    DOUBLE_QUOTE },
74     { "amp", 3,        '&'  },
75     { "apos", 4,    SINGLE_QUOTE },
76     { "lt",    2,         '<'     },
77     { "gt",    2,        '>'     }
78 };
79 
80 
~StrPair()81 StrPair::~StrPair()
82 {
83     Reset();
84 }
85 
86 
Reset()87 void StrPair::Reset()
88 {
89     if ( flags & NEEDS_DELETE ) {
90         delete [] start;
91     }
92     flags = 0;
93     start = 0;
94     end = 0;
95 }
96 
97 
SetStr(const char * str,int flags)98 void StrPair::SetStr( const char* str, int flags )
99 {
100     Reset();
101     size_t len = strlen( str );
102     start = new char[ len+1 ];
103     memcpy( start, str, len+1 );
104     end = start + len;
105     this->flags = flags | NEEDS_DELETE;
106 }
107 
108 
ParseText(char * p,const char * endTag,int strFlags)109 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
110 {
111     TIXMLASSERT( endTag && *endTag );
112 
113     char* start = p;    // fixme: hides a member
114     char  endChar = *endTag;
115     size_t length = strlen( endTag );
116 
117     // Inner loop of text parsing.
118     while ( *p ) {
119         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
120             Set( start, p, strFlags );
121             return p + length;
122         }
123         ++p;
124     }
125     return 0;
126 }
127 
128 
ParseName(char * p)129 char* StrPair::ParseName( char* p )
130 {
131     char* start = p;
132 
133     if ( !start || !(*start) ) {
134         return 0;
135     }
136 
137     if ( !XMLUtil::IsAlpha( *p ) ) {
138         return 0;
139     }
140 
141     while( *p && (
142                XMLUtil::IsAlphaNum( (unsigned char) *p )
143             || *p == '_'
144             || *p == '-'
145             || *p == '.'
146             || *p == ':' ))
147     {
148         ++p;
149     }
150 
151     if ( p > start ) {
152         Set( start, p, 0 );
153         return p;
154     }
155     return 0;
156 }
157 
158 
159 
GetStr()160 const char* StrPair::GetStr()
161 {
162     if ( flags & NEEDS_FLUSH ) {
163         *end = 0;
164         flags ^= NEEDS_FLUSH;
165 
166         if ( flags ) {
167             char* p = start;    // the read pointer
168             char* q = start;    // the write pointer
169 
170             while( p < end ) {
171                 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
172                     // CR-LF pair becomes LF
173                     // CR alone becomes LF
174                     // LF-CR becomes LF
175                     if ( *(p+1) == LF ) {
176                         p += 2;
177                     }
178                     else {
179                         ++p;
180                     }
181                     *q++ = LF;
182                 }
183                 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
184                     if ( *(p+1) == CR ) {
185                         p += 2;
186                     }
187                     else {
188                         ++p;
189                     }
190                     *q++ = LF;
191                 }
192                 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
193                     // Entities handled by tinyXML2:
194                     // - special entities in the entity table [in/out]
195                     // - numeric character reference [in]
196                     //   &#20013; or &#x4e2d;
197 
198                     if ( *(p+1) == '#' ) {
199                         char buf[10] = { 0 };
200                         int len;
201                         p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
202                         for( int i=0; i<len; ++i ) {
203                             *q++ = buf[i];
204                         }
205                         TIXMLASSERT( q <= p );
206                     }
207                     else {
208                         int i=0;
209                         for(; i<NUM_ENTITIES; ++i ) {
210                             if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
211                                  && *(p+entities[i].length+1) == ';' )
212                             {
213                                 // Found an entity convert;
214                                 *q = entities[i].value;
215                                 ++q;
216                                 p += entities[i].length + 2;
217                                 break;
218                             }
219                         }
220                         if ( i == NUM_ENTITIES ) {
221                             // fixme: treat as error?
222                             ++p;
223                             ++q;
224                         }
225                     }
226                 }
227                 else {
228                     *q = *p;
229                     ++p;
230                     ++q;
231                 }
232             }
233             *q = 0;
234         }
235         flags = (flags & NEEDS_DELETE);
236     }
237     return start;
238 }
239 
240 
241 
242 
243 // --------- XMLUtil ----------- //
244 
ReadBOM(const char * p,bool * bom)245 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
246 {
247     *bom = false;
248     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
249     // Check for BOM:
250     if (    *(pu+0) == TIXML_UTF_LEAD_0
251          && *(pu+1) == TIXML_UTF_LEAD_1
252          && *(pu+2) == TIXML_UTF_LEAD_2 )
253     {
254         *bom = true;
255         p += 3;
256     }
257     return p;
258 }
259 
260 
ConvertUTF32ToUTF8(unsigned long input,char * output,int * length)261 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
262 {
263     const unsigned long BYTE_MASK = 0xBF;
264     const unsigned long BYTE_MARK = 0x80;
265     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
266 
267     if (input < 0x80)
268         *length = 1;
269     else if ( input < 0x800 )
270         *length = 2;
271     else if ( input < 0x10000 )
272         *length = 3;
273     else if ( input < 0x200000 )
274         *length = 4;
275     else
276         { *length = 0; return; }    // This code won't covert this correctly anyway.
277 
278     output += *length;
279 
280     // Scary scary fall throughs.
281     switch (*length)
282     {
283         case 4:
284             --output;
285             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
286             input >>= 6;
287         case 3:
288             --output;
289             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
290             input >>= 6;
291         case 2:
292             --output;
293             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
294             input >>= 6;
295         case 1:
296             --output;
297             *output = (char)(input | FIRST_BYTE_MARK[*length]);
298     }
299 }
300 
301 
GetCharacterRef(const char * p,char * value,int * length)302 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
303 {
304     // Presume an entity, and pull it out.
305     *length = 0;
306 
307     if ( *(p+1) == '#' && *(p+2) )
308     {
309         unsigned long ucs = 0;
310         ptrdiff_t delta = 0;
311         unsigned mult = 1;
312 
313         if ( *(p+2) == 'x' )
314         {
315             // Hexadecimal.
316             if ( !*(p+3) ) return 0;
317 
318             const char* q = p+3;
319             q = strchr( q, ';' );
320 
321             if ( !q || !*q ) return 0;
322 
323             delta = q-p;
324             --q;
325 
326             while ( *q != 'x' )
327             {
328                 if ( *q >= '0' && *q <= '9' )
329                     ucs += mult * (*q - '0');
330                 else if ( *q >= 'a' && *q <= 'f' )
331                     ucs += mult * (*q - 'a' + 10);
332                 else if ( *q >= 'A' && *q <= 'F' )
333                     ucs += mult * (*q - 'A' + 10 );
334                 else
335                     return 0;
336                 mult *= 16;
337                 --q;
338             }
339         }
340         else
341         {
342             // Decimal.
343             if ( !*(p+2) ) return 0;
344 
345             const char* q = p+2;
346             q = strchr( q, ';' );
347 
348             if ( !q || !*q ) return 0;
349 
350             delta = q-p;
351             --q;
352 
353             while ( *q != '#' )
354             {
355                 if ( *q >= '0' && *q <= '9' )
356                     ucs += mult * (*q - '0');
357                 else
358                     return 0;
359                 mult *= 10;
360                 --q;
361             }
362         }
363         // convert the UCS to UTF-8
364         ConvertUTF32ToUTF8( ucs, value, length );
365         return p + delta + 1;
366     }
367     return p+1;
368 }
369 
370 
ToStr(int v,char * buffer,int bufferSize)371 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
372 {
373     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
374 }
375 
376 
ToStr(unsigned v,char * buffer,int bufferSize)377 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
378 {
379     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
380 }
381 
382 
ToStr(bool v,char * buffer,int bufferSize)383 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
384 {
385     TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
386 }
387 
388 
ToStr(float v,char * buffer,int bufferSize)389 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
390 {
391     TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
392 }
393 
394 
ToStr(double v,char * buffer,int bufferSize)395 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
396 {
397     TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
398 }
399 
400 
ToInt(const char * str,int * value)401 bool XMLUtil::ToInt( const char* str, int* value )
402 {
403     if ( TIXML_SSCANF( str, "%d", value ) == 1 )
404         return true;
405     return false;
406 }
407 
ToUnsigned(const char * str,unsigned * value)408 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
409 {
410     if ( TIXML_SSCANF( str, "%u", value ) == 1 )
411         return true;
412     return false;
413 }
414 
ToBool(const char * str,bool * value)415 bool XMLUtil::ToBool( const char* str, bool* value )
416 {
417     int ival = 0;
418     if ( ToInt( str, &ival )) {
419         *value = (ival==0) ? false : true;
420         return true;
421     }
422     if ( StringEqual( str, "true" ) ) {
423         *value = true;
424         return true;
425     }
426     else if ( StringEqual( str, "false" ) ) {
427         *value = false;
428         return true;
429     }
430     return false;
431 }
432 
433 
ToFloat(const char * str,float * value)434 bool XMLUtil::ToFloat( const char* str, float* value )
435 {
436     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
437         return true;
438     }
439     return false;
440 }
441 
ToDouble(const char * str,double * value)442 bool XMLUtil::ToDouble( const char* str, double* value )
443 {
444     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
445         return true;
446     }
447     return false;
448 }
449 
450 
Identify(char * p,XMLNode ** node)451 char* XMLDocument::Identify( char* p, XMLNode** node )
452 {
453     XMLNode* returnNode = 0;
454     char* start = p;
455     p = XMLUtil::SkipWhiteSpace( p );
456     if( !p || !*p )
457     {
458         return p;
459     }
460 
461     // What is this thing?
462     // - Elements start with a letter or underscore, but xml is reserved.
463     // - Comments: <!--
464     // - Decleration: <?
465     // - Everthing else is unknown to tinyxml.
466     //
467 
468     static const char* xmlHeader        = { "<?" };
469     static const char* commentHeader    = { "<!--" };
470     static const char* dtdHeader        = { "<!" };
471     static const char* cdataHeader        = { "<![CDATA[" };
472     static const char* elementHeader    = { "<" };    // and a header for everything else; check last.
473 
474     static const int xmlHeaderLen        = 2;
475     static const int commentHeaderLen    = 4;
476     static const int dtdHeaderLen        = 2;
477     static const int cdataHeaderLen        = 9;
478     static const int elementHeaderLen    = 1;
479 
480 #if defined(_MSC_VER)
481 #pragma warning ( push )
482 #pragma warning ( disable : 4127 )
483 #endif
484     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool
485     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
486 #if defined(_MSC_VER)
487 #pragma warning (pop)
488 #endif
489     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
490         returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
491         returnNode->memPool = &commentPool;
492         p += xmlHeaderLen;
493     }
494     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
495         returnNode = new (commentPool.Alloc()) XMLComment( this );
496         returnNode->memPool = &commentPool;
497         p += commentHeaderLen;
498     }
499     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
500         XMLText* text = new (textPool.Alloc()) XMLText( this );
501         returnNode = text;
502         returnNode->memPool = &textPool;
503         p += cdataHeaderLen;
504         text->SetCData( true );
505     }
506     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
507         returnNode = new (commentPool.Alloc()) XMLUnknown( this );
508         returnNode->memPool = &commentPool;
509         p += dtdHeaderLen;
510     }
511     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
512         returnNode = new (elementPool.Alloc()) XMLElement( this );
513         returnNode->memPool = &elementPool;
514         p += elementHeaderLen;
515     }
516     else {
517         returnNode = new (textPool.Alloc()) XMLText( this );
518         returnNode->memPool = &textPool;
519         p = start;    // Back it up, all the text counts.
520     }
521 
522     *node = returnNode;
523     return p;
524 }
525 
526 
Accept(XMLVisitor * visitor) const527 bool XMLDocument::Accept( XMLVisitor* visitor ) const
528 {
529     if ( visitor->VisitEnter( *this ) )
530     {
531         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
532         {
533             if ( !node->Accept( visitor ) )
534                 break;
535         }
536     }
537     return visitor->VisitExit( *this );
538 }
539 
540 
541 // --------- XMLNode ----------- //
542 
XMLNode(XMLDocument * doc)543 XMLNode::XMLNode( XMLDocument* doc ) :
544     document( doc ),
545     parent( 0 ),
546     firstChild( 0 ), lastChild( 0 ),
547     prev( 0 ), next( 0 )
548 {
549 }
550 
551 
~XMLNode()552 XMLNode::~XMLNode()
553 {
554     DeleteChildren();
555     if ( parent ) {
556         parent->Unlink( this );
557     }
558 }
559 
560 
SetValue(const char * str,bool staticMem)561 void XMLNode::SetValue( const char* str, bool staticMem )
562 {
563     if ( staticMem )
564         value.SetInternedStr( str );
565     else
566         value.SetStr( str );
567 }
568 
569 
DeleteChildren()570 void XMLNode::DeleteChildren()
571 {
572     while( firstChild ) {
573         XMLNode* node = firstChild;
574         Unlink( node );
575 
576         DELETE_NODE( node );
577     }
578     firstChild = lastChild = 0;
579 }
580 
581 
Unlink(XMLNode * child)582 void XMLNode::Unlink( XMLNode* child )
583 {
584     TIXMLASSERT( child->parent == this );
585     if ( child == firstChild )
586         firstChild = firstChild->next;
587     if ( child == lastChild )
588         lastChild = lastChild->prev;
589 
590     if ( child->prev ) {
591         child->prev->next = child->next;
592     }
593     if ( child->next ) {
594         child->next->prev = child->prev;
595     }
596     child->parent = 0;
597 }
598 
599 
DeleteChild(XMLNode * node)600 void XMLNode::DeleteChild( XMLNode* node )
601 {
602     TIXMLASSERT( node->parent == this );
603     DELETE_NODE( node );
604 }
605 
606 
InsertEndChild(XMLNode * addThis)607 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
608 {
609     if ( lastChild ) {
610         TIXMLASSERT( firstChild );
611         TIXMLASSERT( lastChild->next == 0 );
612         lastChild->next = addThis;
613         addThis->prev = lastChild;
614         lastChild = addThis;
615 
616         addThis->next = 0;
617     }
618     else {
619         TIXMLASSERT( firstChild == 0 );
620         firstChild = lastChild = addThis;
621 
622         addThis->prev = 0;
623         addThis->next = 0;
624     }
625     addThis->parent = this;
626     return addThis;
627 }
628 
629 
InsertFirstChild(XMLNode * addThis)630 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
631 {
632     if ( firstChild ) {
633         TIXMLASSERT( lastChild );
634         TIXMLASSERT( firstChild->prev == 0 );
635 
636         firstChild->prev = addThis;
637         addThis->next = firstChild;
638         firstChild = addThis;
639 
640         addThis->prev = 0;
641     }
642     else {
643         TIXMLASSERT( lastChild == 0 );
644         firstChild = lastChild = addThis;
645 
646         addThis->prev = 0;
647         addThis->next = 0;
648     }
649     addThis->parent = this;
650     return addThis;
651 }
652 
653 
InsertAfterChild(XMLNode * afterThis,XMLNode * addThis)654 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
655 {
656     TIXMLASSERT( afterThis->parent == this );
657     if ( afterThis->parent != this )
658         return 0;
659 
660     if ( afterThis->next == 0 ) {
661         // The last node or the only node.
662         return InsertEndChild( addThis );
663     }
664     addThis->prev = afterThis;
665     addThis->next = afterThis->next;
666     afterThis->next->prev = addThis;
667     afterThis->next = addThis;
668     addThis->parent = this;
669     return addThis;
670 }
671 
672 
673 
674 
FirstChildElement(const char * value) const675 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
676 {
677     for( XMLNode* node=firstChild; node; node=node->next ) {
678         XMLElement* element = node->ToElement();
679         if ( element ) {
680             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
681                 return element;
682             }
683         }
684     }
685     return 0;
686 }
687 
688 
LastChildElement(const char * value) const689 const XMLElement* XMLNode::LastChildElement( const char* value ) const
690 {
691     for( XMLNode* node=lastChild; node; node=node->prev ) {
692         XMLElement* element = node->ToElement();
693         if ( element ) {
694             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
695                 return element;
696             }
697         }
698     }
699     return 0;
700 }
701 
702 
NextSiblingElement(const char * value) const703 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
704 {
705     for( XMLNode* element=this->next; element; element = element->next ) {
706         if (    element->ToElement()
707              && (!value || XMLUtil::StringEqual( value, element->Value() )))
708         {
709             return element->ToElement();
710         }
711     }
712     return 0;
713 }
714 
715 
PreviousSiblingElement(const char * value) const716 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
717 {
718     for( XMLNode* element=this->prev; element; element = element->prev ) {
719         if (    element->ToElement()
720              && (!value || XMLUtil::StringEqual( value, element->Value() )))
721         {
722             return element->ToElement();
723         }
724     }
725     return 0;
726 }
727 
728 
ParseDeep(char * p,StrPair * parentEnd)729 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
730 {
731     // This is a recursive method, but thinking about it "at the current level"
732     // it is a pretty simple flat list:
733     //        <foo/>
734     //        <!-- comment -->
735     //
736     // With a special case:
737     //        <foo>
738     //        </foo>
739     //        <!-- comment -->
740     //
741     // Where the closing element (/foo) *must* be the next thing after the opening
742     // element, and the names must match. BUT the tricky bit is that the closing
743     // element will be read by the child.
744     //
745     // 'endTag' is the end tag for this node, it is returned by a call to a child.
746     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
747 
748     while( p && *p ) {
749         XMLNode* node = 0;
750 
751         p = document->Identify( p, &node );
752         if ( p == 0 || node == 0 ) {
753             break;
754         }
755 
756         StrPair endTag;
757         p = node->ParseDeep( p, &endTag );
758         if ( !p ) {
759             DELETE_NODE( node );
760             node = 0;
761             if ( !document->Error() ) {
762                 document->SetError( XML_ERROR_PARSING, 0, 0 );
763             }
764             break;
765         }
766 
767         // We read the end tag. Return it to the parent.
768         if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
769             if ( parentEnd ) {
770                 *parentEnd = static_cast<XMLElement*>(node)->value;
771             }
772             DELETE_NODE( node );
773             return p;
774         }
775 
776         // Handle an end tag returned to this level.
777         // And handle a bunch of annoying errors.
778         XMLElement* ele = node->ToElement();
779         if ( ele ) {
780             if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
781                 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
782                 p = 0;
783             }
784             else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
785                 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
786                 p = 0;
787             }
788             else if ( !endTag.Empty() ) {
789                 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
790                     document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
791                     p = 0;
792                 }
793             }
794         }
795         if ( p == 0 ) {
796             DELETE_NODE( node );
797             node = 0;
798         }
799         if ( node ) {
800             this->InsertEndChild( node );
801         }
802     }
803     return 0;
804 }
805 
806 // --------- XMLText ---------- //
ParseDeep(char * p,StrPair *)807 char* XMLText::ParseDeep( char* p, StrPair* )
808 {
809     const char* start = p;
810     if ( this->CData() ) {
811         p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
812         if ( !p ) {
813             document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
814         }
815         return p;
816     }
817     else {
818         p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
819         if ( !p ) {
820             document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
821         }
822         if ( p && *p ) {
823             return p-1;
824         }
825     }
826     return 0;
827 }
828 
829 
ShallowClone(XMLDocument * doc) const830 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
831 {
832     if ( !doc ) {
833         doc = document;
834     }
835     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
836     text->SetCData( this->CData() );
837     return text;
838 }
839 
840 
ShallowEqual(const XMLNode * compare) const841 bool XMLText::ShallowEqual( const XMLNode* compare ) const
842 {
843     return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
844 }
845 
846 
Accept(XMLVisitor * visitor) const847 bool XMLText::Accept( XMLVisitor* visitor ) const
848 {
849     return visitor->Visit( *this );
850 }
851 
852 
853 // --------- XMLComment ---------- //
854 
XMLComment(XMLDocument * doc)855 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
856 {
857 }
858 
859 
~XMLComment()860 XMLComment::~XMLComment()
861 {
862     //printf( "~XMLComment\n" );
863 }
864 
865 
ParseDeep(char * p,StrPair *)866 char* XMLComment::ParseDeep( char* p, StrPair* )
867 {
868     // Comment parses as text.
869     const char* start = p;
870     p = value.ParseText( p, "-->", StrPair::COMMENT );
871     if ( p == 0 ) {
872         document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
873     }
874     return p;
875 }
876 
877 
ShallowClone(XMLDocument * doc) const878 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
879 {
880     if ( !doc ) {
881         doc = document;
882     }
883     XMLComment* comment = doc->NewComment( Value() );    // fixme: this will always allocate memory. Intern?
884     return comment;
885 }
886 
887 
ShallowEqual(const XMLNode * compare) const888 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
889 {
890     return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
891 }
892 
893 
Accept(XMLVisitor * visitor) const894 bool XMLComment::Accept( XMLVisitor* visitor ) const
895 {
896     return visitor->Visit( *this );
897 }
898 
899 
900 // --------- XMLDeclaration ---------- //
901 
XMLDeclaration(XMLDocument * doc)902 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
903 {
904 }
905 
906 
~XMLDeclaration()907 XMLDeclaration::~XMLDeclaration()
908 {
909     //printf( "~XMLDeclaration\n" );
910 }
911 
912 
ParseDeep(char * p,StrPair *)913 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
914 {
915     // Declaration parses as text.
916     const char* start = p;
917     p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
918     if ( p == 0 ) {
919         document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
920     }
921     return p;
922 }
923 
924 
ShallowClone(XMLDocument * doc) const925 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
926 {
927     if ( !doc ) {
928         doc = document;
929     }
930     XMLDeclaration* dec = doc->NewDeclaration( Value() );    // fixme: this will always allocate memory. Intern?
931     return dec;
932 }
933 
934 
ShallowEqual(const XMLNode * compare) const935 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
936 {
937     return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
938 }
939 
940 
941 
Accept(XMLVisitor * visitor) const942 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
943 {
944     return visitor->Visit( *this );
945 }
946 
947 // --------- XMLUnknown ---------- //
948 
XMLUnknown(XMLDocument * doc)949 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
950 {
951 }
952 
953 
~XMLUnknown()954 XMLUnknown::~XMLUnknown()
955 {
956 }
957 
958 
ParseDeep(char * p,StrPair *)959 char* XMLUnknown::ParseDeep( char* p, StrPair* )
960 {
961     // Unknown parses as text.
962     const char* start = p;
963 
964     p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
965     if ( !p ) {
966         document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
967     }
968     return p;
969 }
970 
971 
ShallowClone(XMLDocument * doc) const972 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
973 {
974     if ( !doc ) {
975         doc = document;
976     }
977     XMLUnknown* text = doc->NewUnknown( Value() );    // fixme: this will always allocate memory. Intern?
978     return text;
979 }
980 
981 
ShallowEqual(const XMLNode * compare) const982 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
983 {
984     return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
985 }
986 
987 
Accept(XMLVisitor * visitor) const988 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
989 {
990     return visitor->Visit( *this );
991 }
992 
993 // --------- XMLAttribute ---------- //
ParseDeep(char * p,bool processEntities)994 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
995 {
996     // Parse using the name rules: bug fix, was using ParseText before
997     p = name.ParseName( p );
998     if ( !p || !*p ) return 0;
999 
1000     // Skip white space before =
1001     p = XMLUtil::SkipWhiteSpace( p );
1002     if ( !p || *p != '=' ) return 0;
1003 
1004     ++p;    // move up to opening quote
1005     p = XMLUtil::SkipWhiteSpace( p );
1006     if ( *p != '\"' && *p != '\'' ) return 0;
1007 
1008     char endTag[2] = { *p, 0 };
1009     ++p;    // move past opening quote
1010 
1011     p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1012     return p;
1013 }
1014 
1015 
SetName(const char * n)1016 void XMLAttribute::SetName( const char* n )
1017 {
1018     name.SetStr( n );
1019 }
1020 
1021 
QueryIntValue(int * value) const1022 int XMLAttribute::QueryIntValue( int* value ) const
1023 {
1024     if ( XMLUtil::ToInt( Value(), value ))
1025         return XML_NO_ERROR;
1026     return XML_WRONG_ATTRIBUTE_TYPE;
1027 }
1028 
1029 
QueryUnsignedValue(unsigned int * value) const1030 int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1031 {
1032     if ( XMLUtil::ToUnsigned( Value(), value ))
1033         return XML_NO_ERROR;
1034     return XML_WRONG_ATTRIBUTE_TYPE;
1035 }
1036 
1037 
QueryBoolValue(bool * value) const1038 int XMLAttribute::QueryBoolValue( bool* value ) const
1039 {
1040     if ( XMLUtil::ToBool( Value(), value )) {
1041         return XML_NO_ERROR;
1042     }
1043     return XML_WRONG_ATTRIBUTE_TYPE;
1044 }
1045 
1046 
QueryFloatValue(float * value) const1047 int XMLAttribute::QueryFloatValue( float* value ) const
1048 {
1049     if ( XMLUtil::ToFloat( Value(), value ))
1050         return XML_NO_ERROR;
1051     return XML_WRONG_ATTRIBUTE_TYPE;
1052 }
1053 
1054 
QueryDoubleValue(double * value) const1055 int XMLAttribute::QueryDoubleValue( double* value ) const
1056 {
1057     if ( XMLUtil::ToDouble( Value(), value ))
1058         return XML_NO_ERROR;
1059     return XML_WRONG_ATTRIBUTE_TYPE;
1060 }
1061 
1062 
SetAttribute(const char * v)1063 void XMLAttribute::SetAttribute( const char* v )
1064 {
1065     value.SetStr( v );
1066 }
1067 
1068 
SetAttribute(int v)1069 void XMLAttribute::SetAttribute( int v )
1070 {
1071     char buf[BUF_SIZE];
1072     XMLUtil::ToStr( v, buf, BUF_SIZE );
1073     value.SetStr( buf );
1074 }
1075 
1076 
SetAttribute(unsigned v)1077 void XMLAttribute::SetAttribute( unsigned v )
1078 {
1079     char buf[BUF_SIZE];
1080     XMLUtil::ToStr( v, buf, BUF_SIZE );
1081     value.SetStr( buf );
1082 }
1083 
1084 
SetAttribute(bool v)1085 void XMLAttribute::SetAttribute( bool v )
1086 {
1087     char buf[BUF_SIZE];
1088     XMLUtil::ToStr( v, buf, BUF_SIZE );
1089     value.SetStr( buf );
1090 }
1091 
SetAttribute(double v)1092 void XMLAttribute::SetAttribute( double v )
1093 {
1094     char buf[BUF_SIZE];
1095     XMLUtil::ToStr( v, buf, BUF_SIZE );
1096     value.SetStr( buf );
1097 }
1098 
SetAttribute(float v)1099 void XMLAttribute::SetAttribute( float v )
1100 {
1101     char buf[BUF_SIZE];
1102     XMLUtil::ToStr( v, buf, BUF_SIZE );
1103     value.SetStr( buf );
1104 }
1105 
1106 
1107 // --------- XMLElement ---------- //
XMLElement(XMLDocument * doc)1108 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1109     closingType( 0 ),
1110     rootAttribute( 0 )
1111 {
1112 }
1113 
1114 
~XMLElement()1115 XMLElement::~XMLElement()
1116 {
1117     while( rootAttribute ) {
1118         XMLAttribute* next = rootAttribute->next;
1119         DELETE_ATTRIBUTE( rootAttribute );
1120         rootAttribute = next;
1121     }
1122 }
1123 
1124 
FindAttribute(const char * name)1125 XMLAttribute* XMLElement::FindAttribute( const char* name )
1126 {
1127     XMLAttribute* a = 0;
1128     for( a=rootAttribute; a; a = a->next ) {
1129         if ( XMLUtil::StringEqual( a->Name(), name ) )
1130             return a;
1131     }
1132     return 0;
1133 }
1134 
1135 
FindAttribute(const char * name) const1136 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1137 {
1138     XMLAttribute* a = 0;
1139     for( a=rootAttribute; a; a = a->next ) {
1140         if ( XMLUtil::StringEqual( a->Name(), name ) )
1141             return a;
1142     }
1143     return 0;
1144 }
1145 
1146 
Attribute(const char * name,const char * value) const1147 const char* XMLElement::Attribute( const char* name, const char* value ) const
1148 {
1149     const XMLAttribute* a = FindAttribute( name );
1150     if ( !a )
1151         return 0;
1152     if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1153         return a->Value();
1154     return 0;
1155 }
1156 
1157 
GetText() const1158 const char* XMLElement::GetText() const
1159 {
1160     if ( FirstChild() && FirstChild()->ToText() ) {
1161         return FirstChild()->ToText()->Value();
1162     }
1163     return 0;
1164 }
1165 
1166 
QueryIntText(int * _value) const1167 int XMLElement::QueryIntText( int* _value ) const
1168 {
1169     if ( FirstChild() && FirstChild()->ToText() ) {
1170         const char* t = FirstChild()->ToText()->Value();
1171         if ( XMLUtil::ToInt( t, _value ) ) {
1172             return XML_SUCCESS;
1173         }
1174         return XML_CAN_NOT_CONVERT_TEXT;
1175     }
1176     return XML_NO_TEXT_NODE;
1177 }
1178 
1179 
QueryUnsignedText(unsigned * _value) const1180 int XMLElement::QueryUnsignedText( unsigned* _value ) const
1181 {
1182     if ( FirstChild() && FirstChild()->ToText() ) {
1183         const char* t = FirstChild()->ToText()->Value();
1184         if ( XMLUtil::ToUnsigned( t, _value ) ) {
1185             return XML_SUCCESS;
1186         }
1187         return XML_CAN_NOT_CONVERT_TEXT;
1188     }
1189     return XML_NO_TEXT_NODE;
1190 }
1191 
1192 
QueryBoolText(bool * _value) const1193 int XMLElement::QueryBoolText( bool* _value ) const
1194 {
1195     if ( FirstChild() && FirstChild()->ToText() ) {
1196         const char* t = FirstChild()->ToText()->Value();
1197         if ( XMLUtil::ToBool( t, _value ) ) {
1198             return XML_SUCCESS;
1199         }
1200         return XML_CAN_NOT_CONVERT_TEXT;
1201     }
1202     return XML_NO_TEXT_NODE;
1203 }
1204 
1205 
QueryDoubleText(double * _value) const1206 int XMLElement::QueryDoubleText( double* _value ) const
1207 {
1208     if ( FirstChild() && FirstChild()->ToText() ) {
1209         const char* t = FirstChild()->ToText()->Value();
1210         if ( XMLUtil::ToDouble( t, _value ) ) {
1211             return XML_SUCCESS;
1212         }
1213         return XML_CAN_NOT_CONVERT_TEXT;
1214     }
1215     return XML_NO_TEXT_NODE;
1216 }
1217 
1218 
QueryFloatText(float * _value) const1219 int XMLElement::QueryFloatText( float* _value ) const
1220 {
1221     if ( FirstChild() && FirstChild()->ToText() ) {
1222         const char* t = FirstChild()->ToText()->Value();
1223         if ( XMLUtil::ToFloat( t, _value ) ) {
1224             return XML_SUCCESS;
1225         }
1226         return XML_CAN_NOT_CONVERT_TEXT;
1227     }
1228     return XML_NO_TEXT_NODE;
1229 }
1230 
1231 
1232 
FindOrCreateAttribute(const char * name)1233 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1234 {
1235     XMLAttribute* last = 0;
1236     XMLAttribute* attrib = 0;
1237     for( attrib = rootAttribute;
1238          attrib;
1239          last = attrib, attrib = attrib->next )
1240     {
1241         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1242             break;
1243         }
1244     }
1245     if ( !attrib ) {
1246         attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1247         attrib->memPool = &document->attributePool;
1248         if ( last ) {
1249             last->next = attrib;
1250         }
1251         else {
1252             rootAttribute = attrib;
1253         }
1254         attrib->SetName( name );
1255     }
1256     return attrib;
1257 }
1258 
1259 
DeleteAttribute(const char * name)1260 void XMLElement::DeleteAttribute( const char* name )
1261 {
1262     XMLAttribute* prev = 0;
1263     for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1264         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1265             if ( prev ) {
1266                 prev->next = a->next;
1267             }
1268             else {
1269                 rootAttribute = a->next;
1270             }
1271             DELETE_ATTRIBUTE( a );
1272             break;
1273         }
1274         prev = a;
1275     }
1276 }
1277 
1278 
ParseAttributes(char * p)1279 char* XMLElement::ParseAttributes( char* p )
1280 {
1281     const char* start = p;
1282     XMLAttribute* prevAttribute = 0;
1283 
1284     // Read the attributes.
1285     while( p ) {
1286         p = XMLUtil::SkipWhiteSpace( p );
1287         if ( !p || !(*p) ) {
1288             document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
1289             return 0;
1290         }
1291 
1292         // attribute.
1293         if ( XMLUtil::IsAlpha( *p ) ) {
1294             XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1295             attrib->memPool = &document->attributePool;
1296 
1297             p = attrib->ParseDeep( p, document->ProcessEntities() );
1298             if ( !p || Attribute( attrib->Name() ) ) {
1299                 DELETE_ATTRIBUTE( attrib );
1300                 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1301                 return 0;
1302             }
1303             // There is a minor bug here: if the attribute in the source xml
1304             // document is duplicated, it will not be detected and the
1305             // attribute will be doubly added. However, tracking the 'prevAttribute'
1306             // avoids re-scanning the attribute list. Preferring performance for
1307             // now, may reconsider in the future.
1308             if ( prevAttribute ) {
1309                 prevAttribute->next = attrib;
1310             }
1311             else {
1312                 rootAttribute = attrib;
1313             }
1314             prevAttribute = attrib;
1315         }
1316         // end of the tag
1317         else if ( *p == '/' && *(p+1) == '>' ) {
1318             closingType = CLOSED;
1319             return p+2;    // done; sealed element.
1320         }
1321         // end of the tag
1322         else if ( *p == '>' ) {
1323             ++p;
1324             break;
1325         }
1326         else {
1327             document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1328             return 0;
1329         }
1330     }
1331     return p;
1332 }
1333 
1334 
1335 //
1336 //    <ele></ele>
1337 //    <ele>foo<b>bar</b></ele>
1338 //
ParseDeep(char * p,StrPair * strPair)1339 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
1340 {
1341     // Read the element name.
1342     p = XMLUtil::SkipWhiteSpace( p );
1343     if ( !p ) return 0;
1344 
1345     // The closing element is the </element> form. It is
1346     // parsed just like a regular element then deleted from
1347     // the DOM.
1348     if ( *p == '/' ) {
1349         closingType = CLOSING;
1350         ++p;
1351     }
1352 
1353     p = value.ParseName( p );
1354     if ( value.Empty() ) return 0;
1355 
1356     p = ParseAttributes( p );
1357     if ( !p || !*p || closingType )
1358         return p;
1359 
1360     p = XMLNode::ParseDeep( p, strPair );
1361     return p;
1362 }
1363 
1364 
1365 
ShallowClone(XMLDocument * doc) const1366 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1367 {
1368     if ( !doc ) {
1369         doc = document;
1370     }
1371     XMLElement* element = doc->NewElement( Value() );                    // fixme: this will always allocate memory. Intern?
1372     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1373         element->SetAttribute( a->Name(), a->Value() );                    // fixme: this will always allocate memory. Intern?
1374     }
1375     return element;
1376 }
1377 
1378 
ShallowEqual(const XMLNode * compare) const1379 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1380 {
1381     const XMLElement* other = compare->ToElement();
1382     if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1383 
1384         const XMLAttribute* a=FirstAttribute();
1385         const XMLAttribute* b=other->FirstAttribute();
1386 
1387         while ( a && b ) {
1388             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1389                 return false;
1390             }
1391             a = a->Next();
1392             b = b->Next();
1393         }
1394         if ( a || b ) {
1395             // different count
1396             return false;
1397         }
1398         return true;
1399     }
1400     return false;
1401 }
1402 
1403 
Accept(XMLVisitor * visitor) const1404 bool XMLElement::Accept( XMLVisitor* visitor ) const
1405 {
1406     if ( visitor->VisitEnter( *this, rootAttribute ) )
1407     {
1408         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1409         {
1410             if ( !node->Accept( visitor ) )
1411                 break;
1412         }
1413     }
1414     return visitor->VisitExit( *this );
1415 }
1416 
1417 
1418 // --------- XMLDocument ----------- //
XMLDocument(bool _processEntities)1419 XMLDocument::XMLDocument( bool _processEntities ) :
1420     XMLNode( 0 ),
1421     writeBOM( false ),
1422     processEntities( _processEntities ),
1423     errorID( 0 ),
1424     errorStr1( 0 ),
1425     errorStr2( 0 ),
1426     charBuffer( 0 )
1427 {
1428     document = this;    // avoid warning about 'this' in initializer list
1429 }
1430 
1431 
~XMLDocument()1432 XMLDocument::~XMLDocument()
1433 {
1434     DeleteChildren();
1435     delete [] charBuffer;
1436 
1437 #if 0
1438     textPool.Trace( "text" );
1439     elementPool.Trace( "element" );
1440     commentPool.Trace( "comment" );
1441     attributePool.Trace( "attribute" );
1442 #endif
1443 
1444     TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1445     TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1446     TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1447     TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
1448 }
1449 
1450 
InitDocument()1451 void XMLDocument::InitDocument()
1452 {
1453     errorID = XML_NO_ERROR;
1454     errorStr1 = 0;
1455     errorStr2 = 0;
1456 
1457     delete [] charBuffer;
1458     charBuffer = 0;
1459 
1460 }
1461 
1462 
NewElement(const char * name)1463 XMLElement* XMLDocument::NewElement( const char* name )
1464 {
1465     XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1466     ele->memPool = &elementPool;
1467     ele->SetName( name );
1468     return ele;
1469 }
1470 
1471 
NewComment(const char * str)1472 XMLComment* XMLDocument::NewComment( const char* str )
1473 {
1474     XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1475     comment->memPool = &commentPool;
1476     comment->SetValue( str );
1477     return comment;
1478 }
1479 
1480 
NewText(const char * str)1481 XMLText* XMLDocument::NewText( const char* str )
1482 {
1483     XMLText* text = new (textPool.Alloc()) XMLText( this );
1484     text->memPool = &textPool;
1485     text->SetValue( str );
1486     return text;
1487 }
1488 
1489 
NewDeclaration(const char * str)1490 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1491 {
1492     XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1493     dec->memPool = &commentPool;
1494     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1495     return dec;
1496 }
1497 
1498 
NewUnknown(const char * str)1499 XMLUnknown* XMLDocument::NewUnknown( const char* str )
1500 {
1501     XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1502     unk->memPool = &commentPool;
1503     unk->SetValue( str );
1504     return unk;
1505 }
1506 
1507 
LoadFile(const char * filename)1508 int XMLDocument::LoadFile( const char* filename )
1509 {
1510     DeleteChildren();
1511     InitDocument();
1512 
1513 #if defined(_MSC_VER)
1514 #pragma warning ( push )
1515 #pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.
1516 #endif
1517     FILE* fp = fopen( filename, "rb" );
1518 #if defined(_MSC_VER)
1519 #pragma warning ( pop )
1520 #endif
1521     if ( !fp ) {
1522         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1523         return errorID;
1524     }
1525     LoadFile( fp );
1526     fclose( fp );
1527     return errorID;
1528 }
1529 
1530 
LoadFile(FILE * fp)1531 int XMLDocument::LoadFile( FILE* fp )
1532 {
1533     DeleteChildren();
1534     InitDocument();
1535 
1536     fseek( fp, 0, SEEK_END );
1537     unsigned size = ftell( fp );
1538     fseek( fp, 0, SEEK_SET );
1539 
1540     if ( size == 0 ) {
1541         return errorID;
1542     }
1543 
1544     charBuffer = new char[size+1];
1545     size_t read = fread( charBuffer, 1, size, fp );
1546     if ( read != size ) {
1547         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1548         return errorID;
1549     }
1550 
1551     charBuffer[size] = 0;
1552 
1553     const char* p = charBuffer;
1554     p = XMLUtil::SkipWhiteSpace( p );
1555     p = XMLUtil::ReadBOM( p, &writeBOM );
1556     if ( !p || !*p ) {
1557         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1558         return errorID;
1559     }
1560 
1561     ParseDeep( charBuffer + (p-charBuffer), 0 );
1562     return errorID;
1563 }
1564 
1565 
SaveFile(const char * filename)1566 int XMLDocument::SaveFile( const char* filename )
1567 {
1568 #if defined(_MSC_VER)
1569 #pragma warning ( push )
1570 #pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.
1571 #endif
1572     int fd = open(filename, O_RDWR|O_CREAT, 0644);
1573     FILE* fp = fdopen(fd, "w");
1574     //FILE* fp = fopen( filename, "w" );
1575 #if defined(_MSC_VER)
1576 #pragma warning ( pop )
1577 #endif
1578     if ( !fp ) {
1579         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
1580         return errorID;
1581     }
1582     SaveFile(fp);
1583     fclose( fp );
1584     return errorID;
1585 }
1586 
1587 
SaveFile(FILE * fp)1588 int XMLDocument::SaveFile( FILE* fp )
1589 {
1590     XMLPrinter stream( fp );
1591     Print( &stream );
1592     return errorID;
1593 }
1594 
1595 
Parse(const char * p)1596 int XMLDocument::Parse( const char* p )
1597 {
1598     DeleteChildren();
1599     InitDocument();
1600 
1601     if ( !p || !*p ) {
1602         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1603         return errorID;
1604     }
1605     p = XMLUtil::SkipWhiteSpace( p );
1606     p = XMLUtil::ReadBOM( p, &writeBOM );
1607     if ( !p || !*p ) {
1608         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1609         return errorID;
1610     }
1611 
1612     size_t len = strlen( p );
1613     charBuffer = new char[ len+1 ];
1614     memcpy( charBuffer, p, len+1 );
1615 
1616 
1617     ParseDeep( charBuffer, 0 );
1618     return errorID;
1619 }
1620 
1621 
Print(XMLPrinter * streamer)1622 void XMLDocument::Print( XMLPrinter* streamer )
1623 {
1624     XMLPrinter stdStreamer( stdout );
1625     if ( !streamer )
1626         streamer = &stdStreamer;
1627     Accept( streamer );
1628 }
1629 
1630 
SetError(int error,const char * str1,const char * str2)1631 void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1632 {
1633     errorID = error;
1634     errorStr1 = str1;
1635     errorStr2 = str2;
1636 }
1637 
1638 
PrintError() const1639 void XMLDocument::PrintError() const
1640 {
1641     if ( errorID ) {
1642         static const int LEN = 20;
1643         char buf1[LEN] = { 0 };
1644         char buf2[LEN] = { 0 };
1645 
1646         if ( errorStr1 ) {
1647             TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
1648         }
1649         if ( errorStr2 ) {
1650             TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
1651         }
1652 
1653         printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1654                 errorID, buf1, buf2 );
1655     }
1656 }
1657 
1658 
XMLPrinter(FILE * file,bool compact)1659 XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
1660     elementJustOpened( false ),
1661     firstElement( true ),
1662     fp( file ),
1663     depth( 0 ),
1664     textDepth( -1 ),
1665     processEntities( true ),
1666     compactMode( compact )
1667 {
1668     for( int i=0; i<ENTITY_RANGE; ++i ) {
1669         entityFlag[i] = false;
1670         restrictedEntityFlag[i] = false;
1671     }
1672     for( int i=0; i<NUM_ENTITIES; ++i ) {
1673         TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1674         if ( entities[i].value < ENTITY_RANGE ) {
1675             entityFlag[ (int)entities[i].value ] = true;
1676         }
1677     }
1678     restrictedEntityFlag[(int)'&'] = true;
1679     restrictedEntityFlag[(int)'<'] = true;
1680     restrictedEntityFlag[(int)'>'] = true;    // not required, but consistency is nice
1681     buffer.Push( 0 );
1682 }
1683 
1684 
Print(const char * format,...)1685 void XMLPrinter::Print( const char* format, ... )
1686 {
1687     va_list     va;
1688     va_start( va, format );
1689 
1690     if ( fp ) {
1691         vfprintf( fp, format, va );
1692     }
1693     else {
1694         // This seems brutally complex. Haven't figured out a better
1695         // way on windows.
1696         #ifdef _MSC_VER
1697             int len = -1;
1698             int expand = 1000;
1699             while ( len < 0 ) {
1700                 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
1701                 if ( len < 0 ) {
1702                     expand *= 3/2;
1703                     accumulator.PushArr( expand );
1704                 }
1705             }
1706             char* p = buffer.PushArr( len ) - 1;
1707             memcpy( p, accumulator.Mem(), len+1 );
1708         #else
1709             int len = vsnprintf( 0, 0, format, va );
1710             // Close out and re-start the va-args
1711             va_end( va );
1712             va_start( va, format );
1713             char* p = buffer.PushArr( len ) - 1;
1714             vsnprintf( p, len+1, format, va );
1715         #endif
1716     }
1717     va_end( va );
1718 }
1719 
1720 
PrintSpace(int depth)1721 void XMLPrinter::PrintSpace( int depth )
1722 {
1723     for( int i=0; i<depth; ++i ) {
1724         Print( "    " );
1725     }
1726 }
1727 
1728 
PrintString(const char * p,bool restricted)1729 void XMLPrinter::PrintString( const char* p, bool restricted )
1730 {
1731     // Look for runs of bytes between entities to print.
1732     const char* q = p;
1733     const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
1734 
1735     if ( processEntities ) {
1736         while ( *q ) {
1737             // Remember, char is sometimes signed. (How many times has that bitten me?)
1738             if ( *q > 0 && *q < ENTITY_RANGE ) {
1739                 // Check for entities. If one is found, flush
1740                 // the stream up until the entity, write the
1741                 // entity, and keep looking.
1742                 if ( flag[(unsigned)(*q)] ) {
1743                     while ( p < q ) {
1744                         Print( "%c", *p );
1745                         ++p;
1746                     }
1747                     for( int i=0; i<NUM_ENTITIES; ++i ) {
1748                         if ( entities[i].value == *q ) {
1749                             Print( "&%s;", entities[i].pattern );
1750                             break;
1751                         }
1752                     }
1753                     ++p;
1754                 }
1755             }
1756             ++q;
1757         }
1758     }
1759     // Flush the remaining string. This will be the entire
1760     // string if an entity wasn't found.
1761     if ( !processEntities || (q-p > 0) ) {
1762         Print( "%s", p );
1763     }
1764 }
1765 
1766 
PushHeader(bool writeBOM,bool writeDec)1767 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
1768 {
1769     static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1770     if ( writeBOM ) {
1771         Print( "%s", bom );
1772     }
1773     if ( writeDec ) {
1774         PushDeclaration( "xml version=\"1.0\"" );
1775     }
1776 }
1777 
1778 
OpenElement(const char * name)1779 void XMLPrinter::OpenElement( const char* name )
1780 {
1781     if ( elementJustOpened ) {
1782         SealElement();
1783     }
1784     stack.Push( name );
1785 
1786     if ( textDepth < 0 && !firstElement && !compactMode ) {
1787         Print( "\n" );
1788         PrintSpace( depth );
1789     }
1790 
1791     Print( "<%s", name );
1792     elementJustOpened = true;
1793     firstElement = false;
1794     ++depth;
1795 }
1796 
1797 
PushAttribute(const char * name,const char * value)1798 void XMLPrinter::PushAttribute( const char* name, const char* value )
1799 {
1800     TIXMLASSERT( elementJustOpened );
1801     Print( " %s=\"", name );
1802     PrintString( value, false );
1803     Print( "\"" );
1804 }
1805 
1806 
PushAttribute(const char * name,int v)1807 void XMLPrinter::PushAttribute( const char* name, int v )
1808 {
1809     char buf[BUF_SIZE];
1810     XMLUtil::ToStr( v, buf, BUF_SIZE );
1811     PushAttribute( name, buf );
1812 }
1813 
1814 
PushAttribute(const char * name,unsigned v)1815 void XMLPrinter::PushAttribute( const char* name, unsigned v )
1816 {
1817     char buf[BUF_SIZE];
1818     XMLUtil::ToStr( v, buf, BUF_SIZE );
1819     PushAttribute( name, buf );
1820 }
1821 
1822 
PushAttribute(const char * name,bool v)1823 void XMLPrinter::PushAttribute( const char* name, bool v )
1824 {
1825     char buf[BUF_SIZE];
1826     XMLUtil::ToStr( v, buf, BUF_SIZE );
1827     PushAttribute( name, buf );
1828 }
1829 
1830 
PushAttribute(const char * name,double v)1831 void XMLPrinter::PushAttribute( const char* name, double v )
1832 {
1833     char buf[BUF_SIZE];
1834     XMLUtil::ToStr( v, buf, BUF_SIZE );
1835     PushAttribute( name, buf );
1836 }
1837 
1838 
CloseElement()1839 void XMLPrinter::CloseElement()
1840 {
1841     --depth;
1842     const char* name = stack.Pop();
1843 
1844     if ( elementJustOpened ) {
1845         Print( "/>" );
1846     }
1847     else {
1848         if ( textDepth < 0 && !compactMode) {
1849             Print( "\n" );
1850             PrintSpace( depth );
1851         }
1852         Print( "</%s>", name );
1853     }
1854 
1855     if ( textDepth == depth )
1856         textDepth = -1;
1857     if ( depth == 0 && !compactMode)
1858         Print( "\n" );
1859     elementJustOpened = false;
1860 }
1861 
1862 
SealElement()1863 void XMLPrinter::SealElement()
1864 {
1865     elementJustOpened = false;
1866     Print( ">" );
1867 }
1868 
1869 
PushText(const char * text,bool cdata)1870 void XMLPrinter::PushText( const char* text, bool cdata )
1871 {
1872     textDepth = depth-1;
1873 
1874     if ( elementJustOpened ) {
1875         SealElement();
1876     }
1877     if ( cdata ) {
1878         Print( "<![CDATA[" );
1879         Print( "%s", text );
1880         Print( "]]>" );
1881     }
1882     else {
1883         PrintString( text, true );
1884     }
1885 }
1886 
PushText(int value)1887 void XMLPrinter::PushText( int value )
1888 {
1889     char buf[BUF_SIZE];
1890     XMLUtil::ToStr( value, buf, BUF_SIZE );
1891     PushText( buf, false );
1892 }
1893 
1894 
PushText(unsigned value)1895 void XMLPrinter::PushText( unsigned value )
1896 {
1897     char buf[BUF_SIZE];
1898     XMLUtil::ToStr( value, buf, BUF_SIZE );
1899     PushText( buf, false );
1900 }
1901 
1902 
PushText(bool value)1903 void XMLPrinter::PushText( bool value )
1904 {
1905     char buf[BUF_SIZE];
1906     XMLUtil::ToStr( value, buf, BUF_SIZE );
1907     PushText( buf, false );
1908 }
1909 
1910 
PushText(float value)1911 void XMLPrinter::PushText( float value )
1912 {
1913     char buf[BUF_SIZE];
1914     XMLUtil::ToStr( value, buf, BUF_SIZE );
1915     PushText( buf, false );
1916 }
1917 
1918 
PushText(double value)1919 void XMLPrinter::PushText( double value )
1920 {
1921     char buf[BUF_SIZE];
1922     XMLUtil::ToStr( value, buf, BUF_SIZE );
1923     PushText( buf, false );
1924 }
1925 
1926 
PushComment(const char * comment)1927 void XMLPrinter::PushComment( const char* comment )
1928 {
1929     if ( elementJustOpened ) {
1930         SealElement();
1931     }
1932     if ( textDepth < 0 && !firstElement && !compactMode) {
1933         Print( "\n" );
1934         PrintSpace( depth );
1935     }
1936     firstElement = false;
1937     Print( "<!--%s-->", comment );
1938 }
1939 
1940 
PushDeclaration(const char * value)1941 void XMLPrinter::PushDeclaration( const char* value )
1942 {
1943     if ( elementJustOpened ) {
1944         SealElement();
1945     }
1946     if ( textDepth < 0 && !firstElement && !compactMode) {
1947         Print( "\n" );
1948         PrintSpace( depth );
1949     }
1950     firstElement = false;
1951     Print( "<?%s?>", value );
1952 }
1953 
1954 
PushUnknown(const char * value)1955 void XMLPrinter::PushUnknown( const char* value )
1956 {
1957     if ( elementJustOpened ) {
1958         SealElement();
1959     }
1960     if ( textDepth < 0 && !firstElement && !compactMode) {
1961         Print( "\n" );
1962         PrintSpace( depth );
1963     }
1964     firstElement = false;
1965     Print( "<!%s>", value );
1966 }
1967 
1968 
VisitEnter(const XMLDocument & doc)1969 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
1970 {
1971     processEntities = doc.ProcessEntities();
1972     if ( doc.HasBOM() ) {
1973         PushHeader( true, false );
1974     }
1975     return true;
1976 }
1977 
1978 
VisitEnter(const XMLElement & element,const XMLAttribute * attribute)1979 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
1980 {
1981     OpenElement( element.Name() );
1982     while ( attribute ) {
1983         PushAttribute( attribute->Name(), attribute->Value() );
1984         attribute = attribute->Next();
1985     }
1986     return true;
1987 }
1988 
1989 
VisitExit(const XMLElement &)1990 bool XMLPrinter::VisitExit( const XMLElement& )
1991 {
1992     CloseElement();
1993     return true;
1994 }
1995 
1996 
Visit(const XMLText & text)1997 bool XMLPrinter::Visit( const XMLText& text )
1998 {
1999     PushText( text.Value(), text.CData() );
2000     return true;
2001 }
2002 
2003 
Visit(const XMLComment & comment)2004 bool XMLPrinter::Visit( const XMLComment& comment )
2005 {
2006     PushComment( comment.Value() );
2007     return true;
2008 }
2009 
Visit(const XMLDeclaration & declaration)2010 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2011 {
2012     PushDeclaration( declaration.Value() );
2013     return true;
2014 }
2015 
2016 
Visit(const XMLUnknown & unknown)2017 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2018 {
2019     PushUnknown( unknown.Value() );
2020     return true;
2021 }
2022