1 /*
2 www.sourceforge.net/projects/tinyxml
3 Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must
14 not claim that you wrote the original software. If you use this
15 software in a product, an acknowledgment in the product documentation
16 would be appreciated but is not required.
17
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20
21 3. This notice may not be removed or altered from any source
22 distribution.
23 */
24
25 #include <ctype.h>
26
27 #ifdef TIXML_USE_STL
28 #include <sstream>
29 #include <iostream>
30 #endif
31
32 #include "tinyxml.h"
33
34
35 bool TiXmlBase::condenseWhiteSpace = true;
36
37 // Microsoft compiler security
TiXmlFOpen(const char * filename,const char * mode)38 FILE* TiXmlFOpen( const char* filename, const char* mode )
39 {
40 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
41 FILE* fp = 0;
42 errno_t err = fopen_s( &fp, filename, mode );
43 if ( !err && fp )
44 return fp;
45 return 0;
46 #else
47 return fopen( filename, mode );
48 #endif
49 }
50
EncodeString(const TIXML_STRING & str,TIXML_STRING * outString)51 void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
52 {
53 int i=0;
54
55 while( i<(int)str.length() )
56 {
57 unsigned char c = (unsigned char) str[i];
58
59 if ( c == '&'
60 && i < ( (int)str.length() - 2 )
61 && str[i+1] == '#'
62 && str[i+2] == 'x' )
63 {
64 // Hexadecimal character reference.
65 // Pass through unchanged.
66 // © -- copyright symbol, for example.
67 //
68 // The -1 is a bug fix from Rob Laveaux. It keeps
69 // an overflow from happening if there is no ';'.
70 // There are actually 2 ways to exit this loop -
71 // while fails (error case) and break (semicolon found).
72 // However, there is no mechanism (currently) for
73 // this function to return an error.
74 while ( i<(int)str.length()-1 )
75 {
76 outString->append( str.c_str() + i, 1 );
77 ++i;
78 if ( str[i] == ';' )
79 break;
80 }
81 }
82 else if ( c == '&' )
83 {
84 outString->append( entity[0].str, entity[0].strLength );
85 ++i;
86 }
87 else if ( c == '<' )
88 {
89 outString->append( entity[1].str, entity[1].strLength );
90 ++i;
91 }
92 else if ( c == '>' )
93 {
94 outString->append( entity[2].str, entity[2].strLength );
95 ++i;
96 }
97 else if ( c == '\"' )
98 {
99 outString->append( entity[3].str, entity[3].strLength );
100 ++i;
101 }
102 else if ( c == '\'' )
103 {
104 outString->append( entity[4].str, entity[4].strLength );
105 ++i;
106 }
107 else if ( c < 32 )
108 {
109 // Easy pass at non-alpha/numeric/symbol
110 // Below 32 is symbolic.
111 char buf[ 32 ];
112
113 #if defined(TIXML_SNPRINTF)
114 TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
115 #else
116 sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
117 #endif
118
119 //*ME: warning C4267: convert 'size_t' to 'int'
120 //*ME: Int-Cast to make compiler happy ...
121 outString->append( buf, (int)strlen( buf ) );
122 ++i;
123 }
124 else
125 {
126 //char realc = (char) c;
127 //outString->append( &realc, 1 );
128 *outString += (char) c; // somewhat more efficient function call.
129 ++i;
130 }
131 }
132 }
133
134
TiXmlNode(NodeType _type)135 TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
136 {
137 parent = 0;
138 type = _type;
139 firstChild = 0;
140 lastChild = 0;
141 prev = 0;
142 next = 0;
143 }
144
145
~TiXmlNode()146 TiXmlNode::~TiXmlNode()
147 {
148 TiXmlNode* node = firstChild;
149 TiXmlNode* temp = 0;
150
151 while ( node )
152 {
153 temp = node;
154 node = node->next;
155 delete temp;
156 }
157 }
158
159
CopyTo(TiXmlNode * target) const160 void TiXmlNode::CopyTo( TiXmlNode* target ) const
161 {
162 target->SetValue (value.c_str() );
163 target->userData = userData;
164 }
165
166
Clear()167 void TiXmlNode::Clear()
168 {
169 TiXmlNode* node = firstChild;
170 TiXmlNode* temp = 0;
171
172 while ( node )
173 {
174 temp = node;
175 node = node->next;
176 delete temp;
177 }
178
179 firstChild = 0;
180 lastChild = 0;
181 }
182
183
LinkEndChild(TiXmlNode * node)184 TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
185 {
186 assert( node->parent == 0 || node->parent == this );
187 assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
188
189 if ( node->Type() == TiXmlNode::DOCUMENT )
190 {
191 delete node;
192 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
193 return 0;
194 }
195
196 node->parent = this;
197
198 node->prev = lastChild;
199 node->next = 0;
200
201 if ( lastChild )
202 lastChild->next = node;
203 else
204 firstChild = node; // it was an empty list.
205
206 lastChild = node;
207 return node;
208 }
209
210
InsertEndChild(const TiXmlNode & addThis)211 TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
212 {
213 if ( addThis.Type() == TiXmlNode::DOCUMENT )
214 {
215 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
216 return 0;
217 }
218 TiXmlNode* node = addThis.Clone();
219 if ( !node )
220 return 0;
221
222 return LinkEndChild( node );
223 }
224
225
InsertBeforeChild(TiXmlNode * beforeThis,const TiXmlNode & addThis)226 TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
227 {
228 if ( !beforeThis || beforeThis->parent != this ) {
229 return 0;
230 }
231 if ( addThis.Type() == TiXmlNode::DOCUMENT )
232 {
233 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
234 return 0;
235 }
236
237 TiXmlNode* node = addThis.Clone();
238 if ( !node )
239 return 0;
240 node->parent = this;
241
242 node->next = beforeThis;
243 node->prev = beforeThis->prev;
244 if ( beforeThis->prev )
245 {
246 beforeThis->prev->next = node;
247 }
248 else
249 {
250 assert( firstChild == beforeThis );
251 firstChild = node;
252 }
253 beforeThis->prev = node;
254 return node;
255 }
256
257
InsertAfterChild(TiXmlNode * afterThis,const TiXmlNode & addThis)258 TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
259 {
260 if ( !afterThis || afterThis->parent != this ) {
261 return 0;
262 }
263 if ( addThis.Type() == TiXmlNode::DOCUMENT )
264 {
265 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
266 return 0;
267 }
268
269 TiXmlNode* node = addThis.Clone();
270 if ( !node )
271 return 0;
272 node->parent = this;
273
274 node->prev = afterThis;
275 node->next = afterThis->next;
276 if ( afterThis->next )
277 {
278 afterThis->next->prev = node;
279 }
280 else
281 {
282 assert( lastChild == afterThis );
283 lastChild = node;
284 }
285 afterThis->next = node;
286 return node;
287 }
288
289
ReplaceChild(TiXmlNode * replaceThis,const TiXmlNode & withThis)290 TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
291 {
292 if ( replaceThis->parent != this )
293 return 0;
294
295 TiXmlNode* node = withThis.Clone();
296 if ( !node )
297 return 0;
298
299 node->next = replaceThis->next;
300 node->prev = replaceThis->prev;
301
302 if ( replaceThis->next )
303 replaceThis->next->prev = node;
304 else
305 lastChild = node;
306
307 if ( replaceThis->prev )
308 replaceThis->prev->next = node;
309 else
310 firstChild = node;
311
312 delete replaceThis;
313 node->parent = this;
314 return node;
315 }
316
317
RemoveChild(TiXmlNode * removeThis)318 bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
319 {
320 if ( removeThis->parent != this )
321 {
322 assert( 0 );
323 return false;
324 }
325
326 if ( removeThis->next )
327 removeThis->next->prev = removeThis->prev;
328 else
329 lastChild = removeThis->prev;
330
331 if ( removeThis->prev )
332 removeThis->prev->next = removeThis->next;
333 else
334 firstChild = removeThis->next;
335
336 delete removeThis;
337 return true;
338 }
339
FirstChild(const char * _value) const340 const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
341 {
342 const TiXmlNode* node;
343 for ( node = firstChild; node; node = node->next )
344 {
345 if ( strcmp( node->Value(), _value ) == 0 )
346 return node;
347 }
348 return 0;
349 }
350
351
LastChild(const char * _value) const352 const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
353 {
354 const TiXmlNode* node;
355 for ( node = lastChild; node; node = node->prev )
356 {
357 if ( strcmp( node->Value(), _value ) == 0 )
358 return node;
359 }
360 return 0;
361 }
362
363
IterateChildren(const TiXmlNode * previous) const364 const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
365 {
366 if ( !previous )
367 {
368 return FirstChild();
369 }
370 else
371 {
372 assert( previous->parent == this );
373 return previous->NextSibling();
374 }
375 }
376
377
IterateChildren(const char * val,const TiXmlNode * previous) const378 const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
379 {
380 if ( !previous )
381 {
382 return FirstChild( val );
383 }
384 else
385 {
386 assert( previous->parent == this );
387 return previous->NextSibling( val );
388 }
389 }
390
391
NextSibling(const char * _value) const392 const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
393 {
394 const TiXmlNode* node;
395 for ( node = next; node; node = node->next )
396 {
397 if ( strcmp( node->Value(), _value ) == 0 )
398 return node;
399 }
400 return 0;
401 }
402
403
PreviousSibling(const char * _value) const404 const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
405 {
406 const TiXmlNode* node;
407 for ( node = prev; node; node = node->prev )
408 {
409 if ( strcmp( node->Value(), _value ) == 0 )
410 return node;
411 }
412 return 0;
413 }
414
415
RemoveAttribute(const char * name)416 void TiXmlElement::RemoveAttribute( const char * name )
417 {
418 #ifdef TIXML_USE_STL
419 TIXML_STRING str( name );
420 TiXmlAttribute* node = attributeSet.Find( str );
421 #else
422 TiXmlAttribute* node = attributeSet.Find( name );
423 #endif
424 if ( node )
425 {
426 attributeSet.Remove( node );
427 delete node;
428 }
429 }
430
FirstChildElement() const431 const TiXmlElement* TiXmlNode::FirstChildElement() const
432 {
433 const TiXmlNode* node;
434
435 for ( node = FirstChild();
436 node;
437 node = node->NextSibling() )
438 {
439 if ( node->ToElement() )
440 return node->ToElement();
441 }
442 return 0;
443 }
444
445
FirstChildElement(const char * _value) const446 const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
447 {
448 const TiXmlNode* node;
449
450 for ( node = FirstChild( _value );
451 node;
452 node = node->NextSibling( _value ) )
453 {
454 if ( node->ToElement() )
455 return node->ToElement();
456 }
457 return 0;
458 }
459
460
NextSiblingElement() const461 const TiXmlElement* TiXmlNode::NextSiblingElement() const
462 {
463 const TiXmlNode* node;
464
465 for ( node = NextSibling();
466 node;
467 node = node->NextSibling() )
468 {
469 if ( node->ToElement() )
470 return node->ToElement();
471 }
472 return 0;
473 }
474
475
NextSiblingElement(const char * _value) const476 const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
477 {
478 const TiXmlNode* node;
479
480 for ( node = NextSibling( _value );
481 node;
482 node = node->NextSibling( _value ) )
483 {
484 if ( node->ToElement() )
485 return node->ToElement();
486 }
487 return 0;
488 }
489
490
GetDocument() const491 const TiXmlDocument* TiXmlNode::GetDocument() const
492 {
493 const TiXmlNode* node;
494
495 for( node = this; node; node = node->parent )
496 {
497 if ( node->ToDocument() )
498 return node->ToDocument();
499 }
500 return 0;
501 }
502
503
TiXmlElement(const char * _value)504 TiXmlElement::TiXmlElement (const char * _value)
505 : TiXmlNode( TiXmlNode::ELEMENT )
506 {
507 firstChild = lastChild = 0;
508 value = _value;
509 }
510
511
512 #ifdef TIXML_USE_STL
TiXmlElement(const std::string & _value)513 TiXmlElement::TiXmlElement( const std::string& _value )
514 : TiXmlNode( TiXmlNode::ELEMENT )
515 {
516 firstChild = lastChild = 0;
517 value = _value;
518 }
519 #endif
520
521
TiXmlElement(const TiXmlElement & copy)522 TiXmlElement::TiXmlElement( const TiXmlElement& copy)
523 : TiXmlNode( TiXmlNode::ELEMENT )
524 {
525 firstChild = lastChild = 0;
526 copy.CopyTo( this );
527 }
528
529
operator =(const TiXmlElement & base)530 void TiXmlElement::operator=( const TiXmlElement& base )
531 {
532 ClearThis();
533 base.CopyTo( this );
534 }
535
536
~TiXmlElement()537 TiXmlElement::~TiXmlElement()
538 {
539 ClearThis();
540 }
541
542
ClearThis()543 void TiXmlElement::ClearThis()
544 {
545 Clear();
546 while( attributeSet.First() )
547 {
548 TiXmlAttribute* node = attributeSet.First();
549 attributeSet.Remove( node );
550 delete node;
551 }
552 }
553
554
Attribute(const char * name) const555 const char* TiXmlElement::Attribute( const char* name ) const
556 {
557 const TiXmlAttribute* node = attributeSet.Find( name );
558 if ( node )
559 return node->Value();
560 return 0;
561 }
562
563
564 #ifdef TIXML_USE_STL
Attribute(const std::string & name) const565 const std::string* TiXmlElement::Attribute( const std::string& name ) const
566 {
567 const TiXmlAttribute* node = attributeSet.Find( name );
568 if ( node )
569 return &node->ValueStr();
570 return 0;
571 }
572 #endif
573
574
Attribute(const char * name,int * i) const575 const char* TiXmlElement::Attribute( const char* name, int* i ) const
576 {
577 const char* s = Attribute( name );
578 if ( i )
579 {
580 if ( s ) {
581 *i = atoi( s );
582 }
583 else {
584 *i = 0;
585 }
586 }
587 return s;
588 }
589
590
591 #ifdef TIXML_USE_STL
Attribute(const std::string & name,int * i) const592 const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
593 {
594 const std::string* s = Attribute( name );
595 if ( i )
596 {
597 if ( s ) {
598 *i = atoi( s->c_str() );
599 }
600 else {
601 *i = 0;
602 }
603 }
604 return s;
605 }
606 #endif
607
608
Attribute(const char * name,double * d) const609 const char* TiXmlElement::Attribute( const char* name, double* d ) const
610 {
611 const char* s = Attribute( name );
612 if ( d )
613 {
614 if ( s ) {
615 *d = atof( s );
616 }
617 else {
618 *d = 0;
619 }
620 }
621 return s;
622 }
623
624
625 #ifdef TIXML_USE_STL
Attribute(const std::string & name,double * d) const626 const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
627 {
628 const std::string* s = Attribute( name );
629 if ( d )
630 {
631 if ( s ) {
632 *d = atof( s->c_str() );
633 }
634 else {
635 *d = 0;
636 }
637 }
638 return s;
639 }
640 #endif
641
642
QueryIntAttribute(const char * name,int * ival) const643 int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
644 {
645 const TiXmlAttribute* node = attributeSet.Find( name );
646 if ( !node )
647 return TIXML_NO_ATTRIBUTE;
648 return node->QueryIntValue( ival );
649 }
650
651
652 #ifdef TIXML_USE_STL
QueryIntAttribute(const std::string & name,int * ival) const653 int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
654 {
655 const TiXmlAttribute* node = attributeSet.Find( name );
656 if ( !node )
657 return TIXML_NO_ATTRIBUTE;
658 return node->QueryIntValue( ival );
659 }
660 #endif
661
662
QueryDoubleAttribute(const char * name,double * dval) const663 int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
664 {
665 const TiXmlAttribute* node = attributeSet.Find( name );
666 if ( !node )
667 return TIXML_NO_ATTRIBUTE;
668 return node->QueryDoubleValue( dval );
669 }
670
671
672 #ifdef TIXML_USE_STL
QueryDoubleAttribute(const std::string & name,double * dval) const673 int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
674 {
675 const TiXmlAttribute* node = attributeSet.Find( name );
676 if ( !node )
677 return TIXML_NO_ATTRIBUTE;
678 return node->QueryDoubleValue( dval );
679 }
680 #endif
681
682
SetAttribute(const char * name,int val)683 void TiXmlElement::SetAttribute( const char * name, int val )
684 {
685 char buf[64];
686 #if defined(TIXML_SNPRINTF)
687 TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
688 #else
689 sprintf( buf, "%d", val );
690 #endif
691 SetAttribute( name, buf );
692 }
693
694
695 #ifdef TIXML_USE_STL
SetAttribute(const std::string & name,int val)696 void TiXmlElement::SetAttribute( const std::string& name, int val )
697 {
698 std::ostringstream oss;
699 oss << val;
700 SetAttribute( name, oss.str() );
701 }
702 #endif
703
704
SetDoubleAttribute(const char * name,double val)705 void TiXmlElement::SetDoubleAttribute( const char * name, double val )
706 {
707 char buf[256];
708 #if defined(TIXML_SNPRINTF)
709 TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
710 #else
711 sprintf( buf, "%f", val );
712 #endif
713 SetAttribute( name, buf );
714 }
715
716
SetAttribute(const char * cname,const char * cvalue)717 void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
718 {
719 #ifdef TIXML_USE_STL
720 TIXML_STRING _name( cname );
721 TIXML_STRING _value( cvalue );
722 #else
723 const char* _name = cname;
724 const char* _value = cvalue;
725 #endif
726
727 TiXmlAttribute* node = attributeSet.Find( _name );
728 if ( node )
729 {
730 node->SetValue( _value );
731 return;
732 }
733
734 TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
735 if ( attrib )
736 {
737 attributeSet.Add( attrib );
738 }
739 else
740 {
741 TiXmlDocument* document = GetDocument();
742 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
743 }
744 }
745
746
747 #ifdef TIXML_USE_STL
SetAttribute(const std::string & name,const std::string & _value)748 void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
749 {
750 TiXmlAttribute* node = attributeSet.Find( name );
751 if ( node )
752 {
753 node->SetValue( _value );
754 return;
755 }
756
757 TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
758 if ( attrib )
759 {
760 attributeSet.Add( attrib );
761 }
762 else
763 {
764 TiXmlDocument* document = GetDocument();
765 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
766 }
767 }
768 #endif
769
770
Print(FILE * cfile,int depth) const771 void TiXmlElement::Print( FILE* cfile, int depth ) const
772 {
773 int i;
774 assert( cfile );
775 for ( i=0; i<depth; i++ ) {
776 fprintf( cfile, " " );
777 }
778
779 fprintf( cfile, "<%s", value.c_str() );
780
781 const TiXmlAttribute* attrib;
782 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
783 {
784 fprintf( cfile, " " );
785 attrib->Print( cfile, depth );
786 }
787
788 // There are 3 different formatting approaches:
789 // 1) An element without children is printed as a <foo /> node
790 // 2) An element with only a text child is printed as <foo> text </foo>
791 // 3) An element with children is printed on multiple lines.
792 TiXmlNode* node;
793 if ( !firstChild )
794 {
795 fprintf( cfile, " />" );
796 }
797 else if ( firstChild == lastChild && firstChild->ToText() )
798 {
799 fprintf( cfile, ">" );
800 firstChild->Print( cfile, depth + 1 );
801 fprintf( cfile, "</%s>", value.c_str() );
802 }
803 else
804 {
805 fprintf( cfile, ">" );
806
807 for ( node = firstChild; node; node=node->NextSibling() )
808 {
809 if ( !node->ToText() )
810 {
811 fprintf( cfile, "\n" );
812 }
813 node->Print( cfile, depth+1 );
814 }
815 fprintf( cfile, "\n" );
816 for( i=0; i<depth; ++i ) {
817 fprintf( cfile, " " );
818 }
819 fprintf( cfile, "</%s>", value.c_str() );
820 }
821 }
822
823
CopyTo(TiXmlElement * target) const824 void TiXmlElement::CopyTo( TiXmlElement* target ) const
825 {
826 // superclass:
827 TiXmlNode::CopyTo( target );
828
829 // Element class:
830 // Clone the attributes, then clone the children.
831 const TiXmlAttribute* attribute = 0;
832 for( attribute = attributeSet.First();
833 attribute;
834 attribute = attribute->Next() )
835 {
836 target->SetAttribute( attribute->Name(), attribute->Value() );
837 }
838
839 TiXmlNode* node = 0;
840 for ( node = firstChild; node; node = node->NextSibling() )
841 {
842 target->LinkEndChild( node->Clone() );
843 }
844 }
845
Accept(TiXmlVisitor * visitor) const846 bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
847 {
848 if ( visitor->VisitEnter( *this, attributeSet.First() ) )
849 {
850 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
851 {
852 if ( !node->Accept( visitor ) )
853 break;
854 }
855 }
856 return visitor->VisitExit( *this );
857 }
858
859
Clone() const860 TiXmlNode* TiXmlElement::Clone() const
861 {
862 TiXmlElement* clone = new TiXmlElement( Value() );
863 if ( !clone )
864 return 0;
865
866 CopyTo( clone );
867 return clone;
868 }
869
870
GetText() const871 const char* TiXmlElement::GetText() const
872 {
873 const TiXmlNode* child = this->FirstChild();
874 if ( child ) {
875 const TiXmlText* childText = child->ToText();
876 if ( childText ) {
877 return childText->Value();
878 }
879 }
880 return 0;
881 }
882
883
TiXmlDocument()884 TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
885 {
886 tabsize = 4;
887 useMicrosoftBOM = false;
888 ClearError();
889 }
890
TiXmlDocument(const char * documentName)891 TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
892 {
893 tabsize = 4;
894 useMicrosoftBOM = false;
895 value = documentName;
896 ClearError();
897 }
898
899
900 #ifdef TIXML_USE_STL
TiXmlDocument(const std::string & documentName)901 TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
902 {
903 tabsize = 4;
904 useMicrosoftBOM = false;
905 value = documentName;
906 ClearError();
907 }
908 #endif
909
910
TiXmlDocument(const TiXmlDocument & copy)911 TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
912 {
913 copy.CopyTo( this );
914 }
915
916
operator =(const TiXmlDocument & copy)917 void TiXmlDocument::operator=( const TiXmlDocument& copy )
918 {
919 Clear();
920 copy.CopyTo( this );
921 }
922
923
LoadFile(TiXmlEncoding encoding)924 bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
925 {
926 // See STL_STRING_BUG below.
927 //StringToBuffer buf( value );
928
929 return LoadFile( Value(), encoding );
930 }
931
932
SaveFile() const933 bool TiXmlDocument::SaveFile() const
934 {
935 // See STL_STRING_BUG below.
936 // StringToBuffer buf( value );
937 //
938 // if ( buf.buffer && SaveFile( buf.buffer ) )
939 // return true;
940 //
941 // return false;
942 return SaveFile( Value() );
943 }
944
LoadFile(const char * _filename,TiXmlEncoding encoding)945 bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
946 {
947 // There was a really terrifying little bug here. The code:
948 // value = filename
949 // in the STL case, cause the assignment method of the std::string to
950 // be called. What is strange, is that the std::string had the same
951 // address as it's c_str() method, and so bad things happen. Looks
952 // like a bug in the Microsoft STL implementation.
953 // Add an extra string to avoid the crash.
954 TIXML_STRING filename( _filename );
955 value = filename;
956
957 // reading in binary mode so that tinyxml can normalize the EOL
958 FILE* file = TiXmlFOpen( value.c_str (), "rb" );
959
960 if ( file )
961 {
962 bool result = LoadFile( file, encoding );
963 fclose( file );
964 return result;
965 }
966 else
967 {
968 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
969 return false;
970 }
971 }
972
LoadFile(FILE * file,TiXmlEncoding encoding)973 bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
974 {
975 if ( !file )
976 {
977 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
978 return false;
979 }
980
981 // Delete the existing data:
982 Clear();
983 location.Clear();
984
985 // Get the file size, so we can pre-allocate the string. HUGE speed impact.
986 long length = 0;
987 fseek( file, 0, SEEK_END );
988 length = ftell( file );
989 fseek( file, 0, SEEK_SET );
990
991 // Strange case, but good to handle up front.
992 if ( length <= 0 )
993 {
994 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
995 return false;
996 }
997
998 // If we have a file, assume it is all one big XML file, and read it in.
999 // The document parser may decide the document ends sooner than the entire file, however.
1000 TIXML_STRING data;
1001 data.reserve( length );
1002
1003 // Subtle bug here. TinyXml did use fgets. But from the XML spec:
1004 // 2.11 End-of-Line Handling
1005 // <snip>
1006 // <quote>
1007 // ...the XML processor MUST behave as if it normalized all line breaks in external
1008 // parsed entities (including the document entity) on input, before parsing, by translating
1009 // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
1010 // a single #xA character.
1011 // </quote>
1012 //
1013 // It is not clear fgets does that, and certainly isn't clear it works cross platform.
1014 // Generally, you expect fgets to translate from the convention of the OS to the c/unix
1015 // convention, and not work generally.
1016
1017 /*
1018 while( fgets( buf, sizeof(buf), file ) )
1019 {
1020 data += buf;
1021 }
1022 */
1023
1024 char* buf = new char[ length+1 ];
1025 buf[0] = 0;
1026
1027 if ( fread( buf, length, 1, file ) != 1 ) {
1028 delete [] buf;
1029 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1030 return false;
1031 }
1032
1033 const char* lastPos = buf;
1034 const char* p = buf;
1035
1036 buf[length] = 0;
1037 while( *p ) {
1038 assert( p < (buf+length) );
1039 if ( *p == 0xa ) {
1040 // Newline character. No special rules for this. Append all the characters
1041 // since the last string, and include the newline.
1042 data.append( lastPos, (p-lastPos+1) ); // append, include the newline
1043 ++p; // move past the newline
1044 lastPos = p; // and point to the new buffer (may be 0)
1045 assert( p <= (buf+length) );
1046 }
1047 else if ( *p == 0xd ) {
1048 // Carriage return. Append what we have so far, then
1049 // handle moving forward in the buffer.
1050 if ( (p-lastPos) > 0 ) {
1051 data.append( lastPos, p-lastPos ); // do not add the CR
1052 }
1053 data += (char)0xa; // a proper newline
1054
1055 if ( *(p+1) == 0xa ) {
1056 // Carriage return - new line sequence
1057 p += 2;
1058 lastPos = p;
1059 assert( p <= (buf+length) );
1060 }
1061 else {
1062 // it was followed by something else...that is presumably characters again.
1063 ++p;
1064 lastPos = p;
1065 assert( p <= (buf+length) );
1066 }
1067 }
1068 else {
1069 ++p;
1070 }
1071 }
1072 // Handle any left over characters.
1073 if ( p-lastPos ) {
1074 data.append( lastPos, p-lastPos );
1075 }
1076 delete [] buf;
1077 buf = 0;
1078
1079 Parse( data.c_str(), 0, encoding );
1080
1081 if ( Error() )
1082 return false;
1083 else
1084 return true;
1085 }
1086
1087
SaveFile(const char * filename) const1088 bool TiXmlDocument::SaveFile( const char * filename ) const
1089 {
1090 // The old c stuff lives on...
1091 FILE* fp = TiXmlFOpen( filename, "w" );
1092 if ( fp )
1093 {
1094 bool result = SaveFile( fp );
1095 fclose( fp );
1096 return result;
1097 }
1098 return false;
1099 }
1100
1101
SaveFile(FILE * fp) const1102 bool TiXmlDocument::SaveFile( FILE* fp ) const
1103 {
1104 if ( useMicrosoftBOM )
1105 {
1106 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
1107 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
1108 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
1109
1110 fputc( TIXML_UTF_LEAD_0, fp );
1111 fputc( TIXML_UTF_LEAD_1, fp );
1112 fputc( TIXML_UTF_LEAD_2, fp );
1113 }
1114 Print( fp, 0 );
1115 return (ferror(fp) == 0);
1116 }
1117
1118
CopyTo(TiXmlDocument * target) const1119 void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
1120 {
1121 TiXmlNode::CopyTo( target );
1122
1123 target->error = error;
1124 target->errorId = errorId;
1125 target->errorDesc = errorDesc;
1126 target->tabsize = tabsize;
1127 target->errorLocation = errorLocation;
1128 target->useMicrosoftBOM = useMicrosoftBOM;
1129
1130 TiXmlNode* node = 0;
1131 for ( node = firstChild; node; node = node->NextSibling() )
1132 {
1133 target->LinkEndChild( node->Clone() );
1134 }
1135 }
1136
1137
Clone() const1138 TiXmlNode* TiXmlDocument::Clone() const
1139 {
1140 TiXmlDocument* clone = new TiXmlDocument();
1141 if ( !clone )
1142 return 0;
1143
1144 CopyTo( clone );
1145 return clone;
1146 }
1147
1148
Print(FILE * cfile,int depth) const1149 void TiXmlDocument::Print( FILE* cfile, int depth ) const
1150 {
1151 assert( cfile );
1152 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
1153 {
1154 node->Print( cfile, depth );
1155 fprintf( cfile, "\n" );
1156 }
1157 }
1158
1159
Accept(TiXmlVisitor * visitor) const1160 bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
1161 {
1162 if ( visitor->VisitEnter( *this ) )
1163 {
1164 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
1165 {
1166 if ( !node->Accept( visitor ) )
1167 break;
1168 }
1169 }
1170 return visitor->VisitExit( *this );
1171 }
1172
1173
Next() const1174 const TiXmlAttribute* TiXmlAttribute::Next() const
1175 {
1176 // We are using knowledge of the sentinel. The sentinel
1177 // have a value or name.
1178 if ( next->value.empty() && next->name.empty() )
1179 return 0;
1180 return next;
1181 }
1182
1183 /*
1184 TiXmlAttribute* TiXmlAttribute::Next()
1185 {
1186 // We are using knowledge of the sentinel. The sentinel
1187 // have a value or name.
1188 if ( next->value.empty() && next->name.empty() )
1189 return 0;
1190 return next;
1191 }
1192 */
1193
Previous() const1194 const TiXmlAttribute* TiXmlAttribute::Previous() const
1195 {
1196 // We are using knowledge of the sentinel. The sentinel
1197 // have a value or name.
1198 if ( prev->value.empty() && prev->name.empty() )
1199 return 0;
1200 return prev;
1201 }
1202
1203 /*
1204 TiXmlAttribute* TiXmlAttribute::Previous()
1205 {
1206 // We are using knowledge of the sentinel. The sentinel
1207 // have a value or name.
1208 if ( prev->value.empty() && prev->name.empty() )
1209 return 0;
1210 return prev;
1211 }
1212 */
1213
Print(FILE * cfile,int,TIXML_STRING * str) const1214 void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
1215 {
1216 TIXML_STRING n, v;
1217
1218 EncodeString( name, &n );
1219 EncodeString( value, &v );
1220
1221 if (value.find ('\"') == TIXML_STRING::npos) {
1222 if ( cfile ) {
1223 fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1224 }
1225 if ( str ) {
1226 (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
1227 }
1228 }
1229 else {
1230 if ( cfile ) {
1231 fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1232 }
1233 if ( str ) {
1234 (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
1235 }
1236 }
1237 }
1238
1239
QueryIntValue(int * ival) const1240 int TiXmlAttribute::QueryIntValue( int* ival ) const
1241 {
1242 if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
1243 return TIXML_SUCCESS;
1244 return TIXML_WRONG_TYPE;
1245 }
1246
QueryDoubleValue(double * dval) const1247 int TiXmlAttribute::QueryDoubleValue( double* dval ) const
1248 {
1249 if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
1250 return TIXML_SUCCESS;
1251 return TIXML_WRONG_TYPE;
1252 }
1253
SetIntValue(int _value)1254 void TiXmlAttribute::SetIntValue( int _value )
1255 {
1256 char buf [64];
1257 #if defined(TIXML_SNPRINTF)
1258 TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
1259 #else
1260 sprintf (buf, "%d", _value);
1261 #endif
1262 SetValue (buf);
1263 }
1264
SetDoubleValue(double _value)1265 void TiXmlAttribute::SetDoubleValue( double _value )
1266 {
1267 char buf [256];
1268 #if defined(TIXML_SNPRINTF)
1269 TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
1270 #else
1271 sprintf (buf, "%lf", _value);
1272 #endif
1273 SetValue (buf);
1274 }
1275
IntValue() const1276 int TiXmlAttribute::IntValue() const
1277 {
1278 return atoi (value.c_str ());
1279 }
1280
DoubleValue() const1281 double TiXmlAttribute::DoubleValue() const
1282 {
1283 return atof (value.c_str ());
1284 }
1285
1286
TiXmlComment(const TiXmlComment & copy)1287 TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
1288 {
1289 copy.CopyTo( this );
1290 }
1291
1292
operator =(const TiXmlComment & base)1293 void TiXmlComment::operator=( const TiXmlComment& base )
1294 {
1295 Clear();
1296 base.CopyTo( this );
1297 }
1298
1299
Print(FILE * cfile,int depth) const1300 void TiXmlComment::Print( FILE* cfile, int depth ) const
1301 {
1302 assert( cfile );
1303 for ( int i=0; i<depth; i++ )
1304 {
1305 fprintf( cfile, " " );
1306 }
1307 fprintf( cfile, "<!--%s-->", value.c_str() );
1308 }
1309
1310
CopyTo(TiXmlComment * target) const1311 void TiXmlComment::CopyTo( TiXmlComment* target ) const
1312 {
1313 TiXmlNode::CopyTo( target );
1314 }
1315
1316
Accept(TiXmlVisitor * visitor) const1317 bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
1318 {
1319 return visitor->Visit( *this );
1320 }
1321
1322
Clone() const1323 TiXmlNode* TiXmlComment::Clone() const
1324 {
1325 TiXmlComment* clone = new TiXmlComment();
1326
1327 if ( !clone )
1328 return 0;
1329
1330 CopyTo( clone );
1331 return clone;
1332 }
1333
1334
Print(FILE * cfile,int depth) const1335 void TiXmlText::Print( FILE* cfile, int depth ) const
1336 {
1337 assert( cfile );
1338 if ( cdata )
1339 {
1340 int i;
1341 fprintf( cfile, "\n" );
1342 for ( i=0; i<depth; i++ ) {
1343 fprintf( cfile, " " );
1344 }
1345 fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output
1346 }
1347 else
1348 {
1349 TIXML_STRING buffer;
1350 EncodeString( value, &buffer );
1351 fprintf( cfile, "%s", buffer.c_str() );
1352 }
1353 }
1354
1355
CopyTo(TiXmlText * target) const1356 void TiXmlText::CopyTo( TiXmlText* target ) const
1357 {
1358 TiXmlNode::CopyTo( target );
1359 target->cdata = cdata;
1360 }
1361
1362
Accept(TiXmlVisitor * visitor) const1363 bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
1364 {
1365 return visitor->Visit( *this );
1366 }
1367
1368
Clone() const1369 TiXmlNode* TiXmlText::Clone() const
1370 {
1371 TiXmlText* clone = 0;
1372 clone = new TiXmlText( "" );
1373
1374 if ( !clone )
1375 return 0;
1376
1377 CopyTo( clone );
1378 return clone;
1379 }
1380
1381
TiXmlDeclaration(const char * _version,const char * _encoding,const char * _standalone)1382 TiXmlDeclaration::TiXmlDeclaration( const char * _version,
1383 const char * _encoding,
1384 const char * _standalone )
1385 : TiXmlNode( TiXmlNode::DECLARATION )
1386 {
1387 version = _version;
1388 encoding = _encoding;
1389 standalone = _standalone;
1390 }
1391
1392
1393 #ifdef TIXML_USE_STL
TiXmlDeclaration(const std::string & _version,const std::string & _encoding,const std::string & _standalone)1394 TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
1395 const std::string& _encoding,
1396 const std::string& _standalone )
1397 : TiXmlNode( TiXmlNode::DECLARATION )
1398 {
1399 version = _version;
1400 encoding = _encoding;
1401 standalone = _standalone;
1402 }
1403 #endif
1404
1405
TiXmlDeclaration(const TiXmlDeclaration & copy)1406 TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
1407 : TiXmlNode( TiXmlNode::DECLARATION )
1408 {
1409 copy.CopyTo( this );
1410 }
1411
1412
operator =(const TiXmlDeclaration & copy)1413 void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
1414 {
1415 Clear();
1416 copy.CopyTo( this );
1417 }
1418
1419
Print(FILE * cfile,int,TIXML_STRING * str) const1420 void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
1421 {
1422 if ( cfile ) fprintf( cfile, "<?xml " );
1423 if ( str ) (*str) += "<?xml ";
1424
1425 if ( !version.empty() ) {
1426 if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
1427 if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
1428 }
1429 if ( !encoding.empty() ) {
1430 if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
1431 if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
1432 }
1433 if ( !standalone.empty() ) {
1434 if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
1435 if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
1436 }
1437 if ( cfile ) fprintf( cfile, "?>" );
1438 if ( str ) (*str) += "?>";
1439 }
1440
1441
CopyTo(TiXmlDeclaration * target) const1442 void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
1443 {
1444 TiXmlNode::CopyTo( target );
1445
1446 target->version = version;
1447 target->encoding = encoding;
1448 target->standalone = standalone;
1449 }
1450
1451
Accept(TiXmlVisitor * visitor) const1452 bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
1453 {
1454 return visitor->Visit( *this );
1455 }
1456
1457
Clone() const1458 TiXmlNode* TiXmlDeclaration::Clone() const
1459 {
1460 TiXmlDeclaration* clone = new TiXmlDeclaration();
1461
1462 if ( !clone )
1463 return 0;
1464
1465 CopyTo( clone );
1466 return clone;
1467 }
1468
1469
Print(FILE * cfile,int depth) const1470 void TiXmlUnknown::Print( FILE* cfile, int depth ) const
1471 {
1472 for ( int i=0; i<depth; i++ )
1473 fprintf( cfile, " " );
1474 fprintf( cfile, "<%s>", value.c_str() );
1475 }
1476
1477
CopyTo(TiXmlUnknown * target) const1478 void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
1479 {
1480 TiXmlNode::CopyTo( target );
1481 }
1482
1483
Accept(TiXmlVisitor * visitor) const1484 bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
1485 {
1486 return visitor->Visit( *this );
1487 }
1488
1489
Clone() const1490 TiXmlNode* TiXmlUnknown::Clone() const
1491 {
1492 TiXmlUnknown* clone = new TiXmlUnknown();
1493
1494 if ( !clone )
1495 return 0;
1496
1497 CopyTo( clone );
1498 return clone;
1499 }
1500
1501
TiXmlAttributeSet()1502 TiXmlAttributeSet::TiXmlAttributeSet()
1503 {
1504 sentinel.next = &sentinel;
1505 sentinel.prev = &sentinel;
1506 }
1507
1508
~TiXmlAttributeSet()1509 TiXmlAttributeSet::~TiXmlAttributeSet()
1510 {
1511 assert( sentinel.next == &sentinel );
1512 assert( sentinel.prev == &sentinel );
1513 }
1514
1515
Add(TiXmlAttribute * addMe)1516 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
1517 {
1518 #ifdef TIXML_USE_STL
1519 assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set.
1520 #else
1521 assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
1522 #endif
1523
1524 addMe->next = &sentinel;
1525 addMe->prev = sentinel.prev;
1526
1527 sentinel.prev->next = addMe;
1528 sentinel.prev = addMe;
1529 }
1530
Remove(TiXmlAttribute * removeMe)1531 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
1532 {
1533 TiXmlAttribute* node;
1534
1535 for( node = sentinel.next; node != &sentinel; node = node->next )
1536 {
1537 if ( node == removeMe )
1538 {
1539 node->prev->next = node->next;
1540 node->next->prev = node->prev;
1541 node->next = 0;
1542 node->prev = 0;
1543 return;
1544 }
1545 }
1546 assert( 0 ); // we tried to remove a non-linked attribute.
1547 }
1548
1549
1550 #ifdef TIXML_USE_STL
Find(const std::string & name) const1551 const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
1552 {
1553 for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1554 {
1555 if ( node->name == name )
1556 return node;
1557 }
1558 return 0;
1559 }
1560
1561 /*
1562 TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
1563 {
1564 for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1565 {
1566 if ( node->name == name )
1567 return node;
1568 }
1569 return 0;
1570 }
1571 */
1572 #endif
1573
1574
Find(const char * name) const1575 const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
1576 {
1577 for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1578 {
1579 if ( strcmp( node->name.c_str(), name ) == 0 )
1580 return node;
1581 }
1582 return 0;
1583 }
1584
1585 /*
1586 TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
1587 {
1588 for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1589 {
1590 if ( strcmp( node->name.c_str(), name ) == 0 )
1591 return node;
1592 }
1593 return 0;
1594 }
1595 */
1596
1597 #ifdef TIXML_USE_STL
operator >>(std::istream & in,TiXmlNode & base)1598 std::istream& operator>> (std::istream & in, TiXmlNode & base)
1599 {
1600 TIXML_STRING tag;
1601 tag.reserve( 8 * 1000 );
1602 base.StreamIn( &in, &tag );
1603
1604 base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1605 return in;
1606 }
1607 #endif
1608
1609
1610 #ifdef TIXML_USE_STL
operator <<(std::ostream & out,const TiXmlNode & base)1611 std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
1612 {
1613 TiXmlPrinter printer;
1614 printer.SetStreamPrinting();
1615 base.Accept( &printer );
1616 out << printer.Str();
1617
1618 return out;
1619 }
1620
1621
operator <<(std::string & out,const TiXmlNode & base)1622 std::string& operator<< (std::string& out, const TiXmlNode& base )
1623 {
1624 TiXmlPrinter printer;
1625 printer.SetStreamPrinting();
1626 base.Accept( &printer );
1627 out.append( printer.Str() );
1628
1629 return out;
1630 }
1631 #endif
1632
1633
FirstChild() const1634 TiXmlHandle TiXmlHandle::FirstChild() const
1635 {
1636 if ( node )
1637 {
1638 TiXmlNode* child = node->FirstChild();
1639 if ( child )
1640 return TiXmlHandle( child );
1641 }
1642 return TiXmlHandle( 0 );
1643 }
1644
1645
FirstChild(const char * value) const1646 TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
1647 {
1648 if ( node )
1649 {
1650 TiXmlNode* child = node->FirstChild( value );
1651 if ( child )
1652 return TiXmlHandle( child );
1653 }
1654 return TiXmlHandle( 0 );
1655 }
1656
1657
FirstChildElement() const1658 TiXmlHandle TiXmlHandle::FirstChildElement() const
1659 {
1660 if ( node )
1661 {
1662 TiXmlElement* child = node->FirstChildElement();
1663 if ( child )
1664 return TiXmlHandle( child );
1665 }
1666 return TiXmlHandle( 0 );
1667 }
1668
1669
FirstChildElement(const char * value) const1670 TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
1671 {
1672 if ( node )
1673 {
1674 TiXmlElement* child = node->FirstChildElement( value );
1675 if ( child )
1676 return TiXmlHandle( child );
1677 }
1678 return TiXmlHandle( 0 );
1679 }
1680
1681
Child(int count) const1682 TiXmlHandle TiXmlHandle::Child( int count ) const
1683 {
1684 if ( node )
1685 {
1686 int i;
1687 TiXmlNode* child = node->FirstChild();
1688 for ( i=0;
1689 child && i<count;
1690 child = child->NextSibling(), ++i )
1691 {
1692 // nothing
1693 }
1694 if ( child )
1695 return TiXmlHandle( child );
1696 }
1697 return TiXmlHandle( 0 );
1698 }
1699
1700
Child(const char * value,int count) const1701 TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
1702 {
1703 if ( node )
1704 {
1705 int i;
1706 TiXmlNode* child = node->FirstChild( value );
1707 for ( i=0;
1708 child && i<count;
1709 child = child->NextSibling( value ), ++i )
1710 {
1711 // nothing
1712 }
1713 if ( child )
1714 return TiXmlHandle( child );
1715 }
1716 return TiXmlHandle( 0 );
1717 }
1718
1719
ChildElement(int count) const1720 TiXmlHandle TiXmlHandle::ChildElement( int count ) const
1721 {
1722 if ( node )
1723 {
1724 int i;
1725 TiXmlElement* child = node->FirstChildElement();
1726 for ( i=0;
1727 child && i<count;
1728 child = child->NextSiblingElement(), ++i )
1729 {
1730 // nothing
1731 }
1732 if ( child )
1733 return TiXmlHandle( child );
1734 }
1735 return TiXmlHandle( 0 );
1736 }
1737
1738
ChildElement(const char * value,int count) const1739 TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
1740 {
1741 if ( node )
1742 {
1743 int i;
1744 TiXmlElement* child = node->FirstChildElement( value );
1745 for ( i=0;
1746 child && i<count;
1747 child = child->NextSiblingElement( value ), ++i )
1748 {
1749 // nothing
1750 }
1751 if ( child )
1752 return TiXmlHandle( child );
1753 }
1754 return TiXmlHandle( 0 );
1755 }
1756
1757
VisitEnter(const TiXmlDocument &)1758 bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
1759 {
1760 return true;
1761 }
1762
VisitExit(const TiXmlDocument &)1763 bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
1764 {
1765 return true;
1766 }
1767
VisitEnter(const TiXmlElement & element,const TiXmlAttribute * firstAttribute)1768 bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
1769 {
1770 DoIndent();
1771 buffer += "<";
1772 buffer += element.Value();
1773
1774 for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
1775 {
1776 buffer += " ";
1777 attrib->Print( 0, 0, &buffer );
1778 }
1779
1780 if ( !element.FirstChild() )
1781 {
1782 buffer += " />";
1783 DoLineBreak();
1784 }
1785 else
1786 {
1787 buffer += ">";
1788 if ( element.FirstChild()->ToText()
1789 && element.LastChild() == element.FirstChild()
1790 && element.FirstChild()->ToText()->CDATA() == false )
1791 {
1792 simpleTextPrint = true;
1793 // no DoLineBreak()!
1794 }
1795 else
1796 {
1797 DoLineBreak();
1798 }
1799 }
1800 ++depth;
1801 return true;
1802 }
1803
1804
VisitExit(const TiXmlElement & element)1805 bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
1806 {
1807 --depth;
1808 if ( !element.FirstChild() )
1809 {
1810 // nothing.
1811 }
1812 else
1813 {
1814 if ( simpleTextPrint )
1815 {
1816 simpleTextPrint = false;
1817 }
1818 else
1819 {
1820 DoIndent();
1821 }
1822 buffer += "</";
1823 buffer += element.Value();
1824 buffer += ">";
1825 DoLineBreak();
1826 }
1827 return true;
1828 }
1829
1830
Visit(const TiXmlText & text)1831 bool TiXmlPrinter::Visit( const TiXmlText& text )
1832 {
1833 if ( text.CDATA() )
1834 {
1835 DoIndent();
1836 buffer += "<![CDATA[";
1837 buffer += text.Value();
1838 buffer += "]]>";
1839 DoLineBreak();
1840 }
1841 else if ( simpleTextPrint )
1842 {
1843 TIXML_STRING str;
1844 TiXmlBase::EncodeString( text.ValueTStr(), &str );
1845 buffer += str;
1846 }
1847 else
1848 {
1849 DoIndent();
1850 TIXML_STRING str;
1851 TiXmlBase::EncodeString( text.ValueTStr(), &str );
1852 buffer += str;
1853 DoLineBreak();
1854 }
1855 return true;
1856 }
1857
1858
Visit(const TiXmlDeclaration & declaration)1859 bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
1860 {
1861 DoIndent();
1862 declaration.Print( 0, 0, &buffer );
1863 DoLineBreak();
1864 return true;
1865 }
1866
1867
Visit(const TiXmlComment & comment)1868 bool TiXmlPrinter::Visit( const TiXmlComment& comment )
1869 {
1870 DoIndent();
1871 buffer += "<!--";
1872 buffer += comment.Value();
1873 buffer += "-->";
1874 DoLineBreak();
1875 return true;
1876 }
1877
1878
Visit(const TiXmlUnknown & unknown)1879 bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
1880 {
1881 DoIndent();
1882 buffer += "<";
1883 buffer += unknown.Value();
1884 buffer += ">";
1885 DoLineBreak();
1886 return true;
1887 }
1888
1889