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