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 // 中 or 中
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