1 /*
2 www.sourceforge.net/projects/tinyxml
3 Original code (2.0 and earlier )copyright (c) 2000-2002 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 #include "tinyxml.h"
27
28 #ifdef TIXML_USE_STL
29 #include <sstream>
30 #endif
31
32
33 bool TiXmlBase::condenseWhiteSpace = true;
34
PutString(const TIXML_STRING & str,TIXML_OSTREAM * stream)35 void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream )
36 {
37 TIXML_STRING buffer;
38 PutString( str, &buffer );
39 (*stream) << buffer;
40 }
41
PutString(const TIXML_STRING & str,TIXML_STRING * outString)42 void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString )
43 {
44 int i=0;
45
46 while( i<(int)str.length() )
47 {
48 unsigned char c = (unsigned char) str[i];
49
50 if ( c == '&'
51 && i < ( (int)str.length() - 2 )
52 && str[i+1] == '#'
53 && str[i+2] == 'x' )
54 {
55 // Hexadecimal character reference.
56 // Pass through unchanged.
57 // © -- copyright symbol, for example.
58 //
59 // The -1 is a bug fix from Rob Laveaux. It keeps
60 // an overflow from happening if there is no ';'.
61 // There are actually 2 ways to exit this loop -
62 // while fails (error case) and break (semicolon found).
63 // However, there is no mechanism (currently) for
64 // this function to return an error.
65 while ( i<(int)str.length()-1 )
66 {
67 outString->append( str.c_str() + i, 1 );
68 ++i;
69 if ( str[i] == ';' )
70 break;
71 }
72 }
73 else if ( c == '&' )
74 {
75 outString->append( entity[0].str, entity[0].strLength );
76 ++i;
77 }
78 else if ( c == '<' )
79 {
80 outString->append( entity[1].str, entity[1].strLength );
81 ++i;
82 }
83 else if ( c == '>' )
84 {
85 outString->append( entity[2].str, entity[2].strLength );
86 ++i;
87 }
88 else if ( c == '\"' )
89 {
90 outString->append( entity[3].str, entity[3].strLength );
91 ++i;
92 }
93 else if ( c == '\'' )
94 {
95 outString->append( entity[4].str, entity[4].strLength );
96 ++i;
97 }
98 else if ( c < 32 )
99 {
100 // Easy pass at non-alpha/numeric/symbol
101 // Below 32 is symbolic.
102 char buf[ 32 ];
103 sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
104 //*ME: warning C4267: convert 'size_t' to 'int'
105 //*ME: Int-Cast to make compiler happy ...
106 outString->append( buf, (int)strlen( buf ) );
107 ++i;
108 }
109 else
110 {
111 //char realc = (char) c;
112 //outString->append( &realc, 1 );
113 *outString += (char) c; // somewhat more efficient function call.
114 ++i;
115 }
116 }
117 }
118
119
120 // <-- Strange class for a bug fix. Search for STL_STRING_BUG
StringToBuffer(const TIXML_STRING & str)121 TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str )
122 {
123 buffer = new char[ str.length()+1 ];
124 if ( buffer )
125 {
126 strcpy( buffer, str.c_str() );
127 }
128 }
129
130
~StringToBuffer()131 TiXmlBase::StringToBuffer::~StringToBuffer()
132 {
133 delete [] buffer;
134 }
135 // End strange bug fix. -->
136
137
TiXmlNode(NodeType _type)138 TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
139 {
140 parent = 0;
141 type = _type;
142 firstChild = 0;
143 lastChild = 0;
144 prev = 0;
145 next = 0;
146 }
147
148
~TiXmlNode()149 TiXmlNode::~TiXmlNode()
150 {
151 TiXmlNode* node = firstChild;
152 TiXmlNode* temp = 0;
153
154 while ( node )
155 {
156 temp = node;
157 node = node->next;
158 delete temp;
159 }
160 }
161
162
CopyTo(TiXmlNode * target) const163 void TiXmlNode::CopyTo( TiXmlNode* target ) const
164 {
165 target->SetValue (value.c_str() );
166 target->userData = userData;
167 }
168
169
Clear()170 void 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
LinkEndChild(TiXmlNode * node)187 TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
188 {
189 node->parent = this;
190
191 node->prev = lastChild;
192 node->next = 0;
193
194 if ( lastChild )
195 lastChild->next = node;
196 else
197 firstChild = node; // it was an empty list.
198
199 lastChild = node;
200 return node;
201 }
202
203
InsertEndChild(const TiXmlNode & addThis)204 TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
205 {
206 TiXmlNode* node = addThis.Clone();
207 if ( !node )
208 return 0;
209
210 return LinkEndChild( node );
211 }
212
213
InsertBeforeChild(TiXmlNode * beforeThis,const TiXmlNode & addThis)214 TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
215 {
216 if ( !beforeThis || beforeThis->parent != this )
217 return 0;
218
219 TiXmlNode* node = addThis.Clone();
220 if ( !node )
221 return 0;
222 node->parent = this;
223
224 node->next = beforeThis;
225 node->prev = beforeThis->prev;
226 if ( beforeThis->prev )
227 {
228 beforeThis->prev->next = node;
229 }
230 else
231 {
232 assert( firstChild == beforeThis );
233 firstChild = node;
234 }
235 beforeThis->prev = node;
236 return node;
237 }
238
239
InsertAfterChild(TiXmlNode * afterThis,const TiXmlNode & addThis)240 TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
241 {
242 if ( !afterThis || afterThis->parent != this )
243 return 0;
244
245 TiXmlNode* node = addThis.Clone();
246 if ( !node )
247 return 0;
248 node->parent = this;
249
250 node->prev = afterThis;
251 node->next = afterThis->next;
252 if ( afterThis->next )
253 {
254 afterThis->next->prev = node;
255 }
256 else
257 {
258 assert( lastChild == afterThis );
259 lastChild = node;
260 }
261 afterThis->next = node;
262 return node;
263 }
264
265
ReplaceChild(TiXmlNode * replaceThis,const TiXmlNode & withThis)266 TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
267 {
268 if ( replaceThis->parent != this )
269 return 0;
270
271 TiXmlNode* node = withThis.Clone();
272 if ( !node )
273 return 0;
274
275 node->next = replaceThis->next;
276 node->prev = replaceThis->prev;
277
278 if ( replaceThis->next )
279 replaceThis->next->prev = node;
280 else
281 lastChild = node;
282
283 if ( replaceThis->prev )
284 replaceThis->prev->next = node;
285 else
286 firstChild = node;
287
288 delete replaceThis;
289 node->parent = this;
290 return node;
291 }
292
293
RemoveChild(TiXmlNode * removeThis)294 bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
295 {
296 if ( removeThis->parent != this )
297 {
298 assert( 0 );
299 return false;
300 }
301
302 if ( removeThis->next )
303 removeThis->next->prev = removeThis->prev;
304 else
305 lastChild = removeThis->prev;
306
307 if ( removeThis->prev )
308 removeThis->prev->next = removeThis->next;
309 else
310 firstChild = removeThis->next;
311
312 delete removeThis;
313 return true;
314 }
315
FirstChild(const char * _value) const316 const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
317 {
318 const TiXmlNode* node;
319 for ( node = firstChild; node; node = node->next )
320 {
321 if ( node->SValue() == _value )
322 return node;
323 }
324 return 0;
325 }
326
327
FirstChild(const char * _value)328 TiXmlNode* TiXmlNode::FirstChild( const char * _value )
329 {
330 TiXmlNode* node;
331 for ( node = firstChild; node; node = node->next )
332 {
333 if ( node->SValue() == _value )
334 return node;
335 }
336 return 0;
337 }
338
339
LastChild(const char * _value) const340 const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
341 {
342 const TiXmlNode* node;
343 for ( node = lastChild; node; node = node->prev )
344 {
345 if ( node->SValue() == _value )
346 return node;
347 }
348 return 0;
349 }
350
LastChild(const char * _value)351 TiXmlNode* TiXmlNode::LastChild( const char * _value )
352 {
353 TiXmlNode* node;
354 for ( node = lastChild; node; node = node->prev )
355 {
356 if ( node->SValue() == _value )
357 return node;
358 }
359 return 0;
360 }
361
IterateChildren(const TiXmlNode * previous) const362 const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
363 {
364 if ( !previous )
365 {
366 return FirstChild();
367 }
368 else
369 {
370 assert( previous->parent == this );
371 return previous->NextSibling();
372 }
373 }
374
IterateChildren(TiXmlNode * previous)375 TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous )
376 {
377 if ( !previous )
378 {
379 return FirstChild();
380 }
381 else
382 {
383 assert( previous->parent == this );
384 return previous->NextSibling();
385 }
386 }
387
IterateChildren(const char * val,const TiXmlNode * previous) const388 const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
389 {
390 if ( !previous )
391 {
392 return FirstChild( val );
393 }
394 else
395 {
396 assert( previous->parent == this );
397 return previous->NextSibling( val );
398 }
399 }
400
IterateChildren(const char * val,TiXmlNode * previous)401 TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous )
402 {
403 if ( !previous )
404 {
405 return FirstChild( val );
406 }
407 else
408 {
409 assert( previous->parent == this );
410 return previous->NextSibling( val );
411 }
412 }
413
NextSibling(const char * _value) const414 const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
415 {
416 const TiXmlNode* node;
417 for ( node = next; node; node = node->next )
418 {
419 if ( node->SValue() == _value )
420 return node;
421 }
422 return 0;
423 }
424
NextSibling(const char * _value)425 TiXmlNode* TiXmlNode::NextSibling( const char * _value )
426 {
427 TiXmlNode* node;
428 for ( node = next; node; node = node->next )
429 {
430 if ( node->SValue() == _value )
431 return node;
432 }
433 return 0;
434 }
435
PreviousSibling(const char * _value) const436 const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
437 {
438 const TiXmlNode* node;
439 for ( node = prev; node; node = node->prev )
440 {
441 if ( node->SValue() == _value )
442 return node;
443 }
444 return 0;
445 }
446
PreviousSibling(const char * _value)447 TiXmlNode* TiXmlNode::PreviousSibling( const char * _value )
448 {
449 TiXmlNode* node;
450 for ( node = prev; node; node = node->prev )
451 {
452 if ( node->SValue() == _value )
453 return node;
454 }
455 return 0;
456 }
457
RemoveAttribute(const char * name)458 void TiXmlElement::RemoveAttribute( const char * name )
459 {
460 TiXmlAttribute* node = attributeSet.Find( name );
461 if ( node )
462 {
463 attributeSet.Remove( node );
464 delete node;
465 }
466 }
467
FirstChildElement() const468 const TiXmlElement* TiXmlNode::FirstChildElement() const
469 {
470 const TiXmlNode* node;
471
472 for ( node = FirstChild();
473 node;
474 node = node->NextSibling() )
475 {
476 if ( node->ToElement() )
477 return node->ToElement();
478 }
479 return 0;
480 }
481
FirstChildElement()482 TiXmlElement* TiXmlNode::FirstChildElement()
483 {
484 TiXmlNode* node;
485
486 for ( node = FirstChild();
487 node;
488 node = node->NextSibling() )
489 {
490 if ( node->ToElement() )
491 return node->ToElement();
492 }
493 return 0;
494 }
495
FirstChildElement(const char * _value) const496 const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
497 {
498 const TiXmlNode* node;
499
500 for ( node = FirstChild( _value );
501 node;
502 node = node->NextSibling( _value ) )
503 {
504 if ( node->ToElement() )
505 return node->ToElement();
506 }
507 return 0;
508 }
509
FirstChildElement(const char * _value)510 TiXmlElement* TiXmlNode::FirstChildElement( const char * _value )
511 {
512 TiXmlNode* node;
513
514 for ( node = FirstChild( _value );
515 node;
516 node = node->NextSibling( _value ) )
517 {
518 if ( node->ToElement() )
519 return node->ToElement();
520 }
521 return 0;
522 }
523
NextSiblingElement() const524 const TiXmlElement* TiXmlNode::NextSiblingElement() const
525 {
526 const TiXmlNode* node;
527
528 for ( node = NextSibling();
529 node;
530 node = node->NextSibling() )
531 {
532 if ( node->ToElement() )
533 return node->ToElement();
534 }
535 return 0;
536 }
537
NextSiblingElement()538 TiXmlElement* TiXmlNode::NextSiblingElement()
539 {
540 TiXmlNode* node;
541
542 for ( node = NextSibling();
543 node;
544 node = node->NextSibling() )
545 {
546 if ( node->ToElement() )
547 return node->ToElement();
548 }
549 return 0;
550 }
551
NextSiblingElement(const char * _value) const552 const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
553 {
554 const TiXmlNode* node;
555
556 for ( node = NextSibling( _value );
557 node;
558 node = node->NextSibling( _value ) )
559 {
560 if ( node->ToElement() )
561 return node->ToElement();
562 }
563 return 0;
564 }
565
NextSiblingElement(const char * _value)566 TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value )
567 {
568 TiXmlNode* node;
569
570 for ( node = NextSibling( _value );
571 node;
572 node = node->NextSibling( _value ) )
573 {
574 if ( node->ToElement() )
575 return node->ToElement();
576 }
577 return 0;
578 }
579
580
GetDocument() const581 const TiXmlDocument* TiXmlNode::GetDocument() const
582 {
583 const TiXmlNode* node;
584
585 for( node = this; node; node = node->parent )
586 {
587 if ( node->ToDocument() )
588 return node->ToDocument();
589 }
590 return 0;
591 }
592
GetDocument()593 TiXmlDocument* TiXmlNode::GetDocument()
594 {
595 TiXmlNode* node;
596
597 for( node = this; node; node = node->parent )
598 {
599 if ( node->ToDocument() )
600 return node->ToDocument();
601 }
602 return 0;
603 }
604
TiXmlElement(const char * _value)605 TiXmlElement::TiXmlElement (const char * _value)
606 : TiXmlNode( TiXmlNode::ELEMENT )
607 {
608 firstChild = lastChild = 0;
609 value = _value;
610 }
611
612
613 #ifdef TIXML_USE_STL
TiXmlElement(const std::string & _value)614 TiXmlElement::TiXmlElement( const std::string& _value )
615 : TiXmlNode( TiXmlNode::ELEMENT )
616 {
617 firstChild = lastChild = 0;
618 value = _value;
619 }
620 #endif
621
622
TiXmlElement(const TiXmlElement & copy)623 TiXmlElement::TiXmlElement( const TiXmlElement& copy)
624 : TiXmlNode( TiXmlNode::ELEMENT )
625 {
626 firstChild = lastChild = 0;
627 copy.CopyTo( this );
628 }
629
630
operator =(const TiXmlElement & base)631 void TiXmlElement::operator=( const TiXmlElement& base )
632 {
633 ClearThis();
634 base.CopyTo( this );
635 }
636
637
~TiXmlElement()638 TiXmlElement::~TiXmlElement()
639 {
640 ClearThis();
641 }
642
643
ClearThis()644 void TiXmlElement::ClearThis()
645 {
646 Clear();
647 while( attributeSet.First() )
648 {
649 TiXmlAttribute* node = attributeSet.First();
650 attributeSet.Remove( node );
651 delete node;
652 }
653 }
654
655
Attribute(const char * name) const656 const char * TiXmlElement::Attribute( const char * name ) const
657 {
658 const TiXmlAttribute* node = attributeSet.Find( name );
659
660 if ( node )
661 return node->Value();
662
663 return 0;
664 }
665
666
Attribute(const char * name,int * i) const667 const char * TiXmlElement::Attribute( const char * name, int* i ) const
668 {
669 const char * s = Attribute( name );
670 if ( i )
671 {
672 if ( s )
673 *i = atoi( s );
674 else
675 *i = 0;
676 }
677 return s;
678 }
679
680
Attribute(const char * name,double * d) const681 const char * TiXmlElement::Attribute( const char * name, double* d ) const
682 {
683 const char * s = Attribute( name );
684 if ( d )
685 {
686 if ( s )
687 *d = atof( s );
688 else
689 *d = 0;
690 }
691 return s;
692 }
693
694
QueryIntAttribute(const char * name,int * ival) const695 int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
696 {
697 const TiXmlAttribute* node = attributeSet.Find( name );
698 if ( !node )
699 return TIXML_NO_ATTRIBUTE;
700
701 return node->QueryIntValue( ival );
702 }
703
704
QueryDoubleAttribute(const char * name,double * dval) const705 int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
706 {
707 const TiXmlAttribute* node = attributeSet.Find( name );
708 if ( !node )
709 return TIXML_NO_ATTRIBUTE;
710
711 return node->QueryDoubleValue( dval );
712 }
713
714
SetAttribute(const char * name,int val)715 void TiXmlElement::SetAttribute( const char * name, int val )
716 {
717 char buf[64];
718 sprintf( buf, "%d", val );
719 SetAttribute( name, buf );
720 }
721
722
SetDoubleAttribute(const char * name,double val)723 void TiXmlElement::SetDoubleAttribute( const char * name, double val )
724 {
725 char buf[256];
726 sprintf( buf, "%f", val );
727 SetAttribute( name, buf );
728 }
729
730
SetAttribute(const char * name,const char * _value)731 void TiXmlElement::SetAttribute( const char * name, const char * _value )
732 {
733 TiXmlAttribute* node = attributeSet.Find( name );
734 if ( node )
735 {
736 node->SetValue( _value );
737 return;
738 }
739
740 TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
741 if ( attrib )
742 {
743 attributeSet.Add( attrib );
744 }
745 else
746 {
747 TiXmlDocument* document = GetDocument();
748 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
749 }
750 }
751
Print(FILE * cfile,int depth) const752 void TiXmlElement::Print( FILE* cfile, int depth ) const
753 {
754 int i;
755 for ( i=0; i<depth; i++ )
756 {
757 fprintf( cfile, " " );
758 }
759
760 fprintf( cfile, "<%s", value.c_str() );
761
762 const TiXmlAttribute* attrib;
763 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
764 {
765 fprintf( cfile, " " );
766 attrib->Print( cfile, depth );
767 }
768
769 // There are 3 different formatting approaches:
770 // 1) An element without children is printed as a <foo /> node
771 // 2) An element with only a text child is printed as <foo> text </foo>
772 // 3) An element with children is printed on multiple lines.
773 TiXmlNode* node;
774 if ( !firstChild )
775 {
776 fprintf( cfile, " />" );
777 }
778 else if ( firstChild == lastChild && firstChild->ToText() )
779 {
780 fprintf( cfile, ">" );
781 firstChild->Print( cfile, depth + 1 );
782 fprintf( cfile, "</%s>", value.c_str() );
783 }
784 else
785 {
786 fprintf( cfile, ">" );
787
788 for ( node = firstChild; node; node=node->NextSibling() )
789 {
790 if ( !node->ToText() )
791 {
792 fprintf( cfile, "\n" );
793 }
794 node->Print( cfile, depth+1 );
795 }
796 fprintf( cfile, "\n" );
797 for( i=0; i<depth; ++i )
798 fprintf( cfile, " " );
799 fprintf( cfile, "</%s>", value.c_str() );
800 }
801 }
802
StreamOut(TIXML_OSTREAM * stream) const803 void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const
804 {
805 (*stream) << "<" << value;
806
807 const TiXmlAttribute* attrib;
808 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
809 {
810 (*stream) << " ";
811 attrib->StreamOut( stream );
812 }
813
814 // If this node has children, give it a closing tag. Else
815 // make it an empty tag.
816 TiXmlNode* node;
817 if ( firstChild )
818 {
819 (*stream) << ">";
820
821 for ( node = firstChild; node; node=node->NextSibling() )
822 {
823 node->StreamOut( stream );
824 }
825 (*stream) << "</" << value << ">";
826 }
827 else
828 {
829 (*stream) << " />";
830 }
831 }
832
833
CopyTo(TiXmlElement * target) const834 void TiXmlElement::CopyTo( TiXmlElement* target ) const
835 {
836 // superclass:
837 TiXmlNode::CopyTo( target );
838
839 // Element class:
840 // Clone the attributes, then clone the children.
841 const TiXmlAttribute* attribute = 0;
842 for( attribute = attributeSet.First();
843 attribute;
844 attribute = attribute->Next() )
845 {
846 target->SetAttribute( attribute->Name(), attribute->Value() );
847 }
848
849 TiXmlNode* node = 0;
850 for ( node = firstChild; node; node = node->NextSibling() )
851 {
852 target->LinkEndChild( node->Clone() );
853 }
854 }
855
856
Clone() const857 TiXmlNode* TiXmlElement::Clone() const
858 {
859 TiXmlElement* clone = new TiXmlElement( Value() );
860 if ( !clone )
861 return 0;
862
863 CopyTo( clone );
864 return clone;
865 }
866
867
TiXmlDocument()868 TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
869 {
870 tabsize = 4;
871 ClearError();
872 }
873
TiXmlDocument(const char * documentName)874 TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
875 {
876 tabsize = 4;
877 value = documentName;
878 ClearError();
879 }
880
881
882 #ifdef TIXML_USE_STL
TiXmlDocument(const std::string & documentName)883 TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
884 {
885 tabsize = 4;
886 value = documentName;
887 ClearError();
888 }
889 #endif
890
891
TiXmlDocument(const TiXmlDocument & copy)892 TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
893 {
894 copy.CopyTo( this );
895 }
896
897
operator =(const TiXmlDocument & copy)898 void TiXmlDocument::operator=( const TiXmlDocument& copy )
899 {
900 Clear();
901 copy.CopyTo( this );
902 }
903
904
LoadFile(TiXmlEncoding encoding)905 bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
906 {
907 // See STL_STRING_BUG below.
908 StringToBuffer buf( value );
909
910 if ( buf.buffer && LoadFile( buf.buffer, encoding ) )
911 return true;
912
913 return false;
914 }
915
916
SaveFile() const917 bool TiXmlDocument::SaveFile() const
918 {
919 // See STL_STRING_BUG below.
920 StringToBuffer buf( value );
921
922 if ( buf.buffer && SaveFile( buf.buffer ) )
923 return true;
924
925 return false;
926 }
927
LoadFile(const char * filename,TiXmlEncoding encoding)928 bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding )
929 {
930 // Delete the existing data:
931 Clear();
932 location.Clear();
933
934 // There was a really terrifying little bug here. The code:
935 // value = filename
936 // in the STL case, cause the assignment method of the std::string to
937 // be called. What is strange, is that the std::string had the same
938 // address as it's c_str() method, and so bad things happen. Looks
939 // like a bug in the Microsoft STL implementation.
940 // See STL_STRING_BUG above.
941 // Fixed with the StringToBuffer class.
942 value = filename;
943
944 FILE* file = fopen( value.c_str (), "r" );
945
946 if ( file )
947 {
948 // Get the file size, so we can pre-allocate the string. HUGE speed impact.
949 long length = 0;
950 fseek( file, 0, SEEK_END );
951 length = ftell( file );
952 fseek( file, 0, SEEK_SET );
953
954 // Strange case, but good to handle up front.
955 if ( length == 0 )
956 {
957 fclose( file );
958 return false;
959 }
960
961 // If we have a file, assume it is all one big XML file, and read it in.
962 // The document parser may decide the document ends sooner than the entire file, however.
963 TIXML_STRING data;
964 data.reserve( length );
965
966 const int BUF_SIZE = 2048;
967 char buf[BUF_SIZE];
968
969 while( fgets( buf, BUF_SIZE, file ) )
970 {
971 data += buf;
972 }
973 fclose( file );
974
975 Parse( data.c_str(), 0, encoding );
976
977 if ( Error() )
978 return false;
979 else
980 return true;
981 }
982 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
983 return false;
984 }
985
SaveFile(const char * filename) const986 bool TiXmlDocument::SaveFile( const char * filename ) const
987 {
988 // The old c stuff lives on...
989 FILE* fp = fopen( filename, "w" );
990 if ( fp )
991 {
992 Print( fp, 0 );
993 fclose( fp );
994 return true;
995 }
996 return false;
997 }
998
999
CopyTo(TiXmlDocument * target) const1000 void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
1001 {
1002 TiXmlNode::CopyTo( target );
1003
1004 target->error = error;
1005 target->errorDesc = errorDesc.c_str ();
1006
1007 TiXmlNode* node = 0;
1008 for ( node = firstChild; node; node = node->NextSibling() )
1009 {
1010 target->LinkEndChild( node->Clone() );
1011 }
1012 }
1013
1014
Clone() const1015 TiXmlNode* TiXmlDocument::Clone() const
1016 {
1017 TiXmlDocument* clone = new TiXmlDocument();
1018 if ( !clone )
1019 return 0;
1020
1021 CopyTo( clone );
1022 return clone;
1023 }
1024
1025
Print(FILE * cfile,int depth) const1026 void TiXmlDocument::Print( FILE* cfile, int depth ) const
1027 {
1028 const TiXmlNode* node;
1029 for ( node=FirstChild(); node; node=node->NextSibling() )
1030 {
1031 node->Print( cfile, depth );
1032 fprintf( cfile, "\n" );
1033 }
1034 }
1035
StreamOut(TIXML_OSTREAM * out) const1036 void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const
1037 {
1038 const TiXmlNode* node;
1039 for ( node=FirstChild(); node; node=node->NextSibling() )
1040 {
1041 node->StreamOut( out );
1042
1043 // Special rule for streams: stop after the root element.
1044 // The stream in code will only read one element, so don't
1045 // write more than one.
1046 if ( node->ToElement() )
1047 break;
1048 }
1049 }
1050
1051
Next() const1052 const TiXmlAttribute* TiXmlAttribute::Next() const
1053 {
1054 // We are using knowledge of the sentinel. The sentinel
1055 // have a value or name.
1056 if ( next->value.empty() && next->name.empty() )
1057 return 0;
1058 return next;
1059 }
1060
Next()1061 TiXmlAttribute* TiXmlAttribute::Next()
1062 {
1063 // We are using knowledge of the sentinel. The sentinel
1064 // have a value or name.
1065 if ( next->value.empty() && next->name.empty() )
1066 return 0;
1067 return next;
1068 }
1069
Previous() const1070 const TiXmlAttribute* TiXmlAttribute::Previous() const
1071 {
1072 // We are using knowledge of the sentinel. The sentinel
1073 // have a value or name.
1074 if ( prev->value.empty() && prev->name.empty() )
1075 return 0;
1076 return prev;
1077 }
1078
Previous()1079 TiXmlAttribute* TiXmlAttribute::Previous()
1080 {
1081 // We are using knowledge of the sentinel. The sentinel
1082 // have a value or name.
1083 if ( prev->value.empty() && prev->name.empty() )
1084 return 0;
1085 return prev;
1086 }
1087
Print(FILE * cfile,int) const1088 void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const
1089 {
1090 TIXML_STRING n, v;
1091
1092 PutString( name, &n );
1093 PutString( value, &v );
1094
1095 if (value.find ('\"') == TIXML_STRING::npos)
1096 fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1097 else
1098 fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1099 }
1100
1101
StreamOut(TIXML_OSTREAM * stream) const1102 void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const
1103 {
1104 if (value.find( '\"' ) != TIXML_STRING::npos)
1105 {
1106 PutString( name, stream );
1107 (*stream) << "=" << "'";
1108 PutString( value, stream );
1109 (*stream) << "'";
1110 }
1111 else
1112 {
1113 PutString( name, stream );
1114 (*stream) << "=" << "\"";
1115 PutString( value, stream );
1116 (*stream) << "\"";
1117 }
1118 }
1119
QueryIntValue(int * ival) const1120 int TiXmlAttribute::QueryIntValue( int* ival ) const
1121 {
1122 if ( sscanf( value.c_str(), "%d", ival ) == 1 )
1123 return TIXML_SUCCESS;
1124 return TIXML_WRONG_TYPE;
1125 }
1126
QueryDoubleValue(double * dval) const1127 int TiXmlAttribute::QueryDoubleValue( double* dval ) const
1128 {
1129 if ( sscanf( value.c_str(), "%lf", dval ) == 1 )
1130 return TIXML_SUCCESS;
1131 return TIXML_WRONG_TYPE;
1132 }
1133
SetIntValue(int _value)1134 void TiXmlAttribute::SetIntValue( int _value )
1135 {
1136 char buf [64];
1137 sprintf (buf, "%d", _value);
1138 SetValue (buf);
1139 }
1140
SetDoubleValue(double _value)1141 void TiXmlAttribute::SetDoubleValue( double _value )
1142 {
1143 char buf [256];
1144 sprintf (buf, "%lf", _value);
1145 SetValue (buf);
1146 }
1147
IntValue() const1148 const int TiXmlAttribute::IntValue() const
1149 {
1150 return atoi (value.c_str ());
1151 }
1152
DoubleValue() const1153 const double TiXmlAttribute::DoubleValue() const
1154 {
1155 return atof (value.c_str ());
1156 }
1157
1158
TiXmlComment(const TiXmlComment & copy)1159 TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
1160 {
1161 copy.CopyTo( this );
1162 }
1163
1164
operator =(const TiXmlComment & base)1165 void TiXmlComment::operator=( const TiXmlComment& base )
1166 {
1167 Clear();
1168 base.CopyTo( this );
1169 }
1170
1171
Print(FILE * cfile,int depth) const1172 void TiXmlComment::Print( FILE* cfile, int depth ) const
1173 {
1174 for ( int i=0; i<depth; i++ )
1175 {
1176 fputs( " ", cfile );
1177 }
1178 fprintf( cfile, "<!--%s-->", value.c_str() );
1179 }
1180
StreamOut(TIXML_OSTREAM * stream) const1181 void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const
1182 {
1183 (*stream) << "<!--";
1184 //PutString( value, stream );
1185 (*stream) << value;
1186 (*stream) << "-->";
1187 }
1188
1189
CopyTo(TiXmlComment * target) const1190 void TiXmlComment::CopyTo( TiXmlComment* target ) const
1191 {
1192 TiXmlNode::CopyTo( target );
1193 }
1194
1195
Clone() const1196 TiXmlNode* TiXmlComment::Clone() const
1197 {
1198 TiXmlComment* clone = new TiXmlComment();
1199
1200 if ( !clone )
1201 return 0;
1202
1203 CopyTo( clone );
1204 return clone;
1205 }
1206
1207
Print(FILE * cfile,int) const1208 void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const
1209 {
1210 TIXML_STRING buffer;
1211 PutString( value, &buffer );
1212 fprintf( cfile, "%s", buffer.c_str() );
1213 }
1214
1215
StreamOut(TIXML_OSTREAM * stream) const1216 void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const
1217 {
1218 PutString( value, stream );
1219 }
1220
1221
CopyTo(TiXmlText * target) const1222 void TiXmlText::CopyTo( TiXmlText* target ) const
1223 {
1224 TiXmlNode::CopyTo( target );
1225 }
1226
1227
Clone() const1228 TiXmlNode* TiXmlText::Clone() const
1229 {
1230 TiXmlText* clone = 0;
1231 clone = new TiXmlText( "" );
1232
1233 if ( !clone )
1234 return 0;
1235
1236 CopyTo( clone );
1237 return clone;
1238 }
1239
1240
TiXmlDeclaration(const char * _version,const char * _encoding,const char * _standalone)1241 TiXmlDeclaration::TiXmlDeclaration( const char * _version,
1242 const char * _encoding,
1243 const char * _standalone )
1244 : TiXmlNode( TiXmlNode::DECLARATION )
1245 {
1246 version = _version;
1247 encoding = _encoding;
1248 standalone = _standalone;
1249 }
1250
1251
1252 #ifdef TIXML_USE_STL
TiXmlDeclaration(const std::string & _version,const std::string & _encoding,const std::string & _standalone)1253 TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
1254 const std::string& _encoding,
1255 const std::string& _standalone )
1256 : TiXmlNode( TiXmlNode::DECLARATION )
1257 {
1258 version = _version;
1259 encoding = _encoding;
1260 standalone = _standalone;
1261 }
1262 #endif
1263
1264
TiXmlDeclaration(const TiXmlDeclaration & copy)1265 TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
1266 : TiXmlNode( TiXmlNode::DECLARATION )
1267 {
1268 copy.CopyTo( this );
1269 }
1270
1271
operator =(const TiXmlDeclaration & copy)1272 void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
1273 {
1274 Clear();
1275 copy.CopyTo( this );
1276 }
1277
1278
Print(FILE * cfile,int) const1279 void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const
1280 {
1281 fprintf (cfile, "<?xml ");
1282
1283 if ( !version.empty() )
1284 fprintf (cfile, "version=\"%s\" ", version.c_str ());
1285 if ( !encoding.empty() )
1286 fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
1287 if ( !standalone.empty() )
1288 fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
1289 fprintf (cfile, "?>");
1290 }
1291
StreamOut(TIXML_OSTREAM * stream) const1292 void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const
1293 {
1294 (*stream) << "<?xml ";
1295
1296 if ( !version.empty() )
1297 {
1298 (*stream) << "version=\"";
1299 PutString( version, stream );
1300 (*stream) << "\" ";
1301 }
1302 if ( !encoding.empty() )
1303 {
1304 (*stream) << "encoding=\"";
1305 PutString( encoding, stream );
1306 (*stream ) << "\" ";
1307 }
1308 if ( !standalone.empty() )
1309 {
1310 (*stream) << "standalone=\"";
1311 PutString( standalone, stream );
1312 (*stream) << "\" ";
1313 }
1314 (*stream) << "?>";
1315 }
1316
1317
CopyTo(TiXmlDeclaration * target) const1318 void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
1319 {
1320 TiXmlNode::CopyTo( target );
1321
1322 target->version = version;
1323 target->encoding = encoding;
1324 target->standalone = standalone;
1325 }
1326
1327
Clone() const1328 TiXmlNode* TiXmlDeclaration::Clone() const
1329 {
1330 TiXmlDeclaration* clone = new TiXmlDeclaration();
1331
1332 if ( !clone )
1333 return 0;
1334
1335 CopyTo( clone );
1336 return clone;
1337 }
1338
1339
Print(FILE * cfile,int depth) const1340 void TiXmlUnknown::Print( FILE* cfile, int depth ) const
1341 {
1342 for ( int i=0; i<depth; i++ )
1343 fprintf( cfile, " " );
1344 fprintf( cfile, "<%s>", value.c_str() );
1345 }
1346
1347
StreamOut(TIXML_OSTREAM * stream) const1348 void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const
1349 {
1350 (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown.
1351 }
1352
1353
CopyTo(TiXmlUnknown * target) const1354 void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
1355 {
1356 TiXmlNode::CopyTo( target );
1357 }
1358
1359
Clone() const1360 TiXmlNode* TiXmlUnknown::Clone() const
1361 {
1362 TiXmlUnknown* clone = new TiXmlUnknown();
1363
1364 if ( !clone )
1365 return 0;
1366
1367 CopyTo( clone );
1368 return clone;
1369 }
1370
1371
TiXmlAttributeSet()1372 TiXmlAttributeSet::TiXmlAttributeSet()
1373 {
1374 sentinel.next = &sentinel;
1375 sentinel.prev = &sentinel;
1376 }
1377
1378
~TiXmlAttributeSet()1379 TiXmlAttributeSet::~TiXmlAttributeSet()
1380 {
1381 assert( sentinel.next == &sentinel );
1382 assert( sentinel.prev == &sentinel );
1383 }
1384
1385
Add(TiXmlAttribute * addMe)1386 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
1387 {
1388 assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
1389
1390 addMe->next = &sentinel;
1391 addMe->prev = sentinel.prev;
1392
1393 sentinel.prev->next = addMe;
1394 sentinel.prev = addMe;
1395 }
1396
Remove(TiXmlAttribute * removeMe)1397 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
1398 {
1399 TiXmlAttribute* node;
1400
1401 for( node = sentinel.next; node != &sentinel; node = node->next )
1402 {
1403 if ( node == removeMe )
1404 {
1405 node->prev->next = node->next;
1406 node->next->prev = node->prev;
1407 node->next = 0;
1408 node->prev = 0;
1409 return;
1410 }
1411 }
1412 assert( 0 ); // we tried to remove a non-linked attribute.
1413 }
1414
Find(const char * name) const1415 const TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const
1416 {
1417 const TiXmlAttribute* node;
1418
1419 for( node = sentinel.next; node != &sentinel; node = node->next )
1420 {
1421 if ( node->name == name )
1422 return node;
1423 }
1424 return 0;
1425 }
1426
Find(const char * name)1427 TiXmlAttribute* TiXmlAttributeSet::Find( const char * name )
1428 {
1429 TiXmlAttribute* node;
1430
1431 for( node = sentinel.next; node != &sentinel; node = node->next )
1432 {
1433 if ( node->name == name )
1434 return node;
1435 }
1436 return 0;
1437 }
1438
1439 #ifdef TIXML_USE_STL
operator >>(TIXML_ISTREAM & in,TiXmlNode & base)1440 TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base)
1441 {
1442 TIXML_STRING tag;
1443 tag.reserve( 8 * 1000 );
1444 base.StreamIn( &in, &tag );
1445
1446 base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1447 return in;
1448 }
1449 #endif
1450
1451
operator <<(TIXML_OSTREAM & out,const TiXmlNode & base)1452 TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base)
1453 {
1454 base.StreamOut (& out);
1455 return out;
1456 }
1457
1458
1459 #ifdef TIXML_USE_STL
operator <<(std::string & out,const TiXmlNode & base)1460 std::string & operator<< (std::string& out, const TiXmlNode& base )
1461 {
1462 std::ostringstream os_stream( std::ostringstream::out );
1463 base.StreamOut( &os_stream );
1464
1465 out.append( os_stream.str() );
1466 return out;
1467 }
1468 #endif
1469
1470
FirstChild() const1471 TiXmlHandle TiXmlHandle::FirstChild() const
1472 {
1473 if ( node )
1474 {
1475 TiXmlNode* child = node->FirstChild();
1476 if ( child )
1477 return TiXmlHandle( child );
1478 }
1479 return TiXmlHandle( 0 );
1480 }
1481
1482
FirstChild(const char * value) const1483 TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
1484 {
1485 if ( node )
1486 {
1487 TiXmlNode* child = node->FirstChild( value );
1488 if ( child )
1489 return TiXmlHandle( child );
1490 }
1491 return TiXmlHandle( 0 );
1492 }
1493
1494
FirstChildElement() const1495 TiXmlHandle TiXmlHandle::FirstChildElement() const
1496 {
1497 if ( node )
1498 {
1499 TiXmlElement* child = node->FirstChildElement();
1500 if ( child )
1501 return TiXmlHandle( child );
1502 }
1503 return TiXmlHandle( 0 );
1504 }
1505
1506
FirstChildElement(const char * value) const1507 TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
1508 {
1509 if ( node )
1510 {
1511 TiXmlElement* child = node->FirstChildElement( value );
1512 if ( child )
1513 return TiXmlHandle( child );
1514 }
1515 return TiXmlHandle( 0 );
1516 }
1517
1518
Child(int count) const1519 TiXmlHandle TiXmlHandle::Child( int count ) const
1520 {
1521 if ( node )
1522 {
1523 int i;
1524 TiXmlNode* child = node->FirstChild();
1525 for ( i=0;
1526 child && i<count;
1527 child = child->NextSibling(), ++i )
1528 {
1529 // nothing
1530 }
1531 if ( child )
1532 return TiXmlHandle( child );
1533 }
1534 return TiXmlHandle( 0 );
1535 }
1536
1537
Child(const char * value,int count) const1538 TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
1539 {
1540 if ( node )
1541 {
1542 int i;
1543 TiXmlNode* child = node->FirstChild( value );
1544 for ( i=0;
1545 child && i<count;
1546 child = child->NextSibling( value ), ++i )
1547 {
1548 // nothing
1549 }
1550 if ( child )
1551 return TiXmlHandle( child );
1552 }
1553 return TiXmlHandle( 0 );
1554 }
1555
1556
ChildElement(int count) const1557 TiXmlHandle TiXmlHandle::ChildElement( int count ) const
1558 {
1559 if ( node )
1560 {
1561 int i;
1562 TiXmlElement* child = node->FirstChildElement();
1563 for ( i=0;
1564 child && i<count;
1565 child = child->NextSiblingElement(), ++i )
1566 {
1567 // nothing
1568 }
1569 if ( child )
1570 return TiXmlHandle( child );
1571 }
1572 return TiXmlHandle( 0 );
1573 }
1574
1575
ChildElement(const char * value,int count) const1576 TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
1577 {
1578 if ( node )
1579 {
1580 int i;
1581 TiXmlElement* child = node->FirstChildElement( value );
1582 for ( i=0;
1583 child && i<count;
1584 child = child->NextSiblingElement( value ), ++i )
1585 {
1586 // nothing
1587 }
1588 if ( child )
1589 return TiXmlHandle( child );
1590 }
1591 return TiXmlHandle( 0 );
1592 }
1593