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