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