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