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