1 /*
2 Copyright (c) 2000 Lee Thomason (www.grinninglizard.com)
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any
6 damages arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any
9 purpose, including commercial applications, and to alter it and
10 redistribute it freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
16
17 2. Altered source versions must be plainly marked as such, and
18 must not be misrepresented as being the original software.
19
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23
24 #include <iostream>
25 #include <sstream>
26 #include <fstream>
27 #include "tinyxml.h"
28 using namespace std;
29
30
31 bool TiXmlBase::condenseWhiteSpace = true;
32
33
PutString(const std::string & str,std::ostream * stream)34 void TiXmlBase::PutString( const std::string& str, std::ostream* stream )
35 {
36 // Scan for the all important '&'
37 unsigned int i=0, j=0;
38
39 while ( i < str.length() )
40 {
41 unsigned next = str.find( '&', i );
42
43 if ( next == string::npos )
44 {
45 stream->write( &str.at( i ), str.length() - i );
46 return;
47 }
48
49 // We found an entity.
50 if ( next - i > 0 )
51 stream->write( &str.at( i ), next - i );
52 i = next;
53
54 // Check for the special "&#x" entitity
55 if ( i < str.length() - 2
56 && str[i] == '&'
57 && str[i+1] == '#'
58 && str[i+2] == 'x' )
59 {
60 stream->put( str[i] );
61 }
62 else
63 {
64 for ( j=0; j<NUM_ENTITY; ++j )
65 {
66 if ( str[i] == entity[j].chr )
67 {
68 stream->write( entity[j].str, entity[j].strLength );
69 break;
70 }
71 }
72 if ( j == NUM_ENTITY )
73 {
74 stream->put( str[i] );
75 }
76 }
77 ++i;
78 }
79 }
80
81
TiXmlNode(NodeType _type)82 TiXmlNode::TiXmlNode( NodeType _type )
83 {
84 parent = 0;
85 type = _type;
86 firstChild = 0;
87 lastChild = 0;
88 prev = 0;
89 next = 0;
90 }
91
92
~TiXmlNode()93 TiXmlNode::~TiXmlNode()
94 {
95 TiXmlNode* node = firstChild;
96 TiXmlNode* temp = 0;
97
98 while ( node )
99 {
100 temp = node;
101 node = node->next;
102 delete temp;
103 }
104 }
105
106
Clear()107 void TiXmlNode::Clear()
108 {
109 TiXmlNode* node = firstChild;
110 TiXmlNode* temp = 0;
111
112 while ( node )
113 {
114 temp = node;
115 node = node->next;
116 delete temp;
117 }
118
119 firstChild = 0;
120 lastChild = 0;
121 }
122
123
LinkEndChild(TiXmlNode * node)124 TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
125 {
126 node->parent = this;
127
128 node->prev = lastChild;
129 node->next = 0;
130
131 if ( lastChild )
132 lastChild->next = node;
133 else
134 firstChild = node; // it was an empty list.
135
136 lastChild = node;
137 return node;
138 }
139
140
InsertEndChild(const TiXmlNode & addThis)141 TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
142 {
143 TiXmlNode* node = addThis.Clone();
144 if ( !node )
145 return 0;
146
147 return LinkEndChild( node );
148 }
149
150
InsertBeforeChild(TiXmlNode * beforeThis,const TiXmlNode & addThis)151 TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
152 {
153 if ( beforeThis->parent != this )
154 return 0;
155
156 TiXmlNode* node = addThis.Clone();
157 if ( !node )
158 return 0;
159 node->parent = this;
160
161 node->next = beforeThis;
162 node->prev = beforeThis->prev;
163 beforeThis->prev->next = node;
164 beforeThis->prev = node;
165 return node;
166 }
167
168
InsertAfterChild(TiXmlNode * afterThis,const TiXmlNode & addThis)169 TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
170 {
171 if ( afterThis->parent != this )
172 return 0;
173
174 TiXmlNode* node = addThis.Clone();
175 if ( !node )
176 return 0;
177 node->parent = this;
178
179 node->prev = afterThis;
180 node->next = afterThis->next;
181 afterThis->next->prev = node;
182 afterThis->next = node;
183 return node;
184 }
185
186
ReplaceChild(TiXmlNode * replaceThis,const TiXmlNode & withThis)187 TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
188 {
189 if ( replaceThis->parent != this )
190 return 0;
191
192 TiXmlNode* node = withThis.Clone();
193 if ( !node )
194 return 0;
195
196 node->next = replaceThis->next;
197 node->prev = replaceThis->prev;
198
199 if ( replaceThis->next )
200 replaceThis->next->prev = node;
201 else
202 lastChild = node;
203
204 if ( replaceThis->prev )
205 replaceThis->prev->next = node;
206 else
207 firstChild = node;
208
209 delete replaceThis;
210 node->parent = this;
211 return node;
212 }
213
214
RemoveChild(TiXmlNode * removeThis)215 bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
216 {
217 if ( removeThis->parent != this )
218 {
219 assert( 0 );
220 return false;
221 }
222
223 if ( removeThis->next )
224 removeThis->next->prev = removeThis->prev;
225 else
226 lastChild = removeThis->prev;
227
228 if ( removeThis->prev )
229 removeThis->prev->next = removeThis->next;
230 else
231 firstChild = removeThis->next;
232
233 delete removeThis;
234 return true;
235 }
236
237
FirstChild(const std::string & value) const238 TiXmlNode* TiXmlNode::FirstChild( const std::string& value ) const
239 {
240 TiXmlNode* node;
241 for ( node = firstChild; node; node = node->next )
242 {
243 if ( node->Value() == value )
244 return node;
245 }
246 return 0;
247 }
248
249
LastChild(const std::string & value) const250 TiXmlNode* TiXmlNode::LastChild( const std::string& value ) const
251 {
252 TiXmlNode* node;
253 for ( node = lastChild; node; node = node->prev )
254 {
255 if ( node->Value() == value )
256 return node;
257 }
258 return 0;
259 }
260
261
IterateChildren(TiXmlNode * previous) const262 TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const
263 {
264 if ( !previous )
265 {
266 return FirstChild();
267 }
268 else
269 {
270 assert( previous->parent == this );
271 return previous->NextSibling();
272 }
273 }
274
275
IterateChildren(const std::string & val,TiXmlNode * previous) const276 TiXmlNode* TiXmlNode::IterateChildren( const std::string& val, TiXmlNode* previous ) const
277 {
278 if ( !previous )
279 {
280 return FirstChild( val );
281 }
282 else
283 {
284 assert( previous->parent == this );
285 return previous->NextSibling( val );
286 }
287 }
288
289
NextSibling(const std::string & value) const290 TiXmlNode* TiXmlNode::NextSibling( const std::string& value ) const
291 {
292 TiXmlNode* node;
293 for ( node = next; node; node = node->next )
294 {
295 if ( node->Value() == value )
296 return node;
297 }
298 return 0;
299 }
300
301
PreviousSibling(const std::string & value) const302 TiXmlNode* TiXmlNode::PreviousSibling( const std::string& value ) const
303 {
304 TiXmlNode* node;
305 for ( node = prev; node; node = node->prev )
306 {
307 if ( node->Value() == value )
308 return node;
309 }
310 return 0;
311 }
312
313
RemoveAttribute(const std::string & name)314 void TiXmlElement::RemoveAttribute( const std::string& name )
315 {
316 TiXmlAttribute* node = attributeSet.Find( name );
317 if ( node )
318 {
319 attributeSet.Remove( node );
320 delete node;
321 }
322 }
323
324
FirstChildElement() const325 TiXmlElement* TiXmlNode::FirstChildElement() const
326 {
327 TiXmlNode* node;
328
329 for ( node = FirstChild();
330 node;
331 node = node->NextSibling() )
332 {
333 if ( node->ToElement() )
334 return node->ToElement();
335 }
336 return 0;
337 }
338
339
FirstChildElement(const std::string & value) const340 TiXmlElement* TiXmlNode::FirstChildElement( const std::string& value ) const
341 {
342 TiXmlNode* node;
343
344 for ( node = FirstChild( value );
345 node;
346 node = node->NextSibling( value ) )
347 {
348 if ( node->ToElement() )
349 return node->ToElement();
350 }
351 return 0;
352 }
353
354
NextSiblingElement() const355 TiXmlElement* TiXmlNode::NextSiblingElement() const
356 {
357 TiXmlNode* node;
358
359 for ( node = NextSibling();
360 node;
361 node = node->NextSibling() )
362 {
363 if ( node->ToElement() )
364 return node->ToElement();
365 }
366 return 0;
367 }
368
369
NextSiblingElement(const std::string & value) const370 TiXmlElement* TiXmlNode::NextSiblingElement( const std::string& value ) const
371 {
372 TiXmlNode* node;
373
374 for ( node = NextSibling( value );
375 node;
376 node = node->NextSibling( value ) )
377 {
378 if ( node->ToElement() )
379 return node->ToElement();
380 }
381 return 0;
382 }
383
384
385
GetDocument() const386 TiXmlDocument* TiXmlNode::GetDocument() const
387 {
388 const TiXmlNode* node;
389
390 for( node = this; node; node = node->parent )
391 {
392 if ( node->ToDocument() )
393 return node->ToDocument();
394 }
395 return 0;
396 }
397
398
399 // TiXmlElement::TiXmlElement()
400 // : TiXmlNode( TiXmlNode::ELEMENT )
401 // {
402 // }
403
TiXmlElement(const std::string & _value)404 TiXmlElement::TiXmlElement( const std::string& _value )
405 : TiXmlNode( TiXmlNode::ELEMENT )
406 {
407 firstChild = lastChild = 0;
408 value = _value;
409 }
410
~TiXmlElement()411 TiXmlElement::~TiXmlElement()
412 {
413 while( attributeSet.First() )
414 {
415 TiXmlAttribute* node = attributeSet.First();
416 attributeSet.Remove( node );
417 delete node;
418 }
419 }
420
Attribute(const std::string & name) const421 const std::string* TiXmlElement::Attribute( const std::string& name ) const
422 {
423 TiXmlAttribute* node = attributeSet.Find( name );
424
425 if ( node )
426 return &(node->Value() );
427
428 return 0;
429 }
430
431
Attribute(const std::string & name,int * i) const432 const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
433 {
434 const std::string* s = Attribute( name );
435 if ( s )
436 *i = atoi( s->c_str() );
437 else
438 *i = 0;
439 return s;
440 }
441
442
SetAttribute(const std::string & name,int val)443 void TiXmlElement::SetAttribute( const std::string& name, int val )
444 {
445 char buf[64];
446 sprintf( buf, "%d", val );
447
448 std::string v = buf;
449
450 SetAttribute( name, v );
451 }
452
453
SetAttribute(const std::string & name,const std::string & value)454 void TiXmlElement::SetAttribute( const std::string& name, const std::string& value )
455 {
456 TiXmlAttribute* node = attributeSet.Find( name );
457 if ( node )
458 {
459 node->SetValue( value );
460 return;
461 }
462
463 TiXmlAttribute* attrib = new TiXmlAttribute( name, value );
464 if ( attrib )
465 {
466 attributeSet.Add( attrib );
467 }
468 else
469 {
470 TiXmlDocument* document = GetDocument();
471 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
472 }
473 }
474
475
Print(FILE * cfile,int depth) const476 void TiXmlElement::Print( FILE* cfile, int depth ) const
477 {
478 int i;
479 for ( i=0; i<depth; i++ )
480 {
481 fprintf( cfile, " " );
482 }
483
484 fprintf( cfile, "<%s", value.c_str() );
485
486 TiXmlAttribute* attrib;
487 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
488 {
489 fprintf( cfile, " " );
490 attrib->Print( cfile, depth );
491 }
492
493 // There are 3 different formatting approaches:
494 // 1) An element without children is printed as a <foo /> node
495 // 2) An element with only a text child is printed as <foo> text </foo>
496 // 3) An element with children is printed on multiple lines.
497 TiXmlNode* node;
498 if ( !firstChild )
499 {
500 fprintf( cfile, " />" );
501 }
502 else if ( firstChild == lastChild && firstChild->ToText() )
503 {
504 fprintf( cfile, ">" );
505 firstChild->Print( cfile, depth + 1 );
506 fprintf( cfile, "</%s>", value.c_str() );
507 }
508 else
509 {
510 fprintf( cfile, ">" );
511
512 for ( node = firstChild; node; node=node->NextSibling() )
513 {
514 if ( !node->ToText() )
515 {
516 fprintf( cfile, "\n" );
517 }
518 node->Print( cfile, depth+1 );
519 }
520 fprintf( cfile, "\n" );
521 for( i=0; i<depth; ++i )
522 fprintf( cfile, " " );
523 fprintf( cfile, "</%s>", value.c_str() );
524 }
525 }
526
527
StreamOut(std::ostream * stream) const528 void TiXmlElement::StreamOut( std::ostream* stream ) const
529 {
530 (*stream) << "<" << value;
531
532 TiXmlAttribute* attrib;
533 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
534 {
535 (*stream) << " ";
536 attrib->StreamOut( stream );
537 }
538
539 // If this node has children, give it a closing tag. Else
540 // make it an empty tag.
541 TiXmlNode* node;
542 if ( firstChild )
543 {
544 (*stream) << ">";
545
546 for ( node = firstChild; node; node=node->NextSibling() )
547 {
548 node->StreamOut( stream );
549 }
550 (*stream) << "</" << value << ">";
551 }
552 else
553 {
554 (*stream) << " />";
555 }
556 }
557
558
Clone() const559 TiXmlNode* TiXmlElement::Clone() const
560 {
561 TiXmlElement* clone = new TiXmlElement( Value() );
562
563 if ( !clone )
564 return 0;
565
566 CopyToClone( clone );
567
568 // Clone the attributes, then clone the children.
569 TiXmlAttribute* attribute = 0;
570 for( attribute = attributeSet.First();
571 attribute;
572 attribute = attribute->Next() )
573 {
574 clone->SetAttribute( attribute->Name(), attribute->Value() );
575 }
576
577 TiXmlNode* node = 0;
578 for ( node = firstChild; node; node = node->NextSibling() )
579 {
580 clone->LinkEndChild( node->Clone() );
581 }
582 return clone;
583 }
584
585
TiXmlDocument()586 TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
587 {
588 error = false;
589 // ignoreWhiteSpace = true;
590 }
591
592
TiXmlDocument(const std::string & documentName)593 TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
594 {
595 // ignoreWhiteSpace = true;
596 value = documentName;
597 error = false;
598 }
599
600
LoadFile()601 bool TiXmlDocument::LoadFile()
602 {
603 return LoadFile( value );
604 }
605
606
SaveFile() const607 bool TiXmlDocument::SaveFile() const
608 {
609 return SaveFile( value );
610 }
611
612
LoadFile(const std::string & filename)613 bool TiXmlDocument::LoadFile( const std::string& filename )
614 {
615 // Delete the existing data:
616 Clear();
617 value = filename;
618
619 FILE* file = fopen( filename.c_str(), "r" );
620
621 if ( file )
622 {
623 // Get the file size, so we can pre-allocate the string. HUGE speed impact.
624 long length = 0;
625 fseek( file, 0, SEEK_END );
626 length = ftell( file );
627 fseek( file, 0, SEEK_SET );
628
629 // If we have a file, assume it is all one big XML file, and read it in.
630 // The document parser may decide the document ends sooner than the entire file, however.
631 std::string data;
632 data.reserve( length );
633
634 const int BUF_SIZE = 2048;
635 char buf[BUF_SIZE];
636
637 while( fgets( buf, BUF_SIZE, file ) )
638 {
639 data += buf;
640 }
641 fclose( file );
642
643 Parse( data.c_str() );
644 if ( !Error() )
645 {
646 return true;
647 }
648 }
649 SetError( TIXML_ERROR_OPENING_FILE );
650 return false;
651 }
652
653
SaveFile(const std::string & filename) const654 bool TiXmlDocument::SaveFile( const std::string& filename ) const
655 {
656 // The old c stuff lives on...
657 FILE* fp = fopen( filename.c_str(), "w" );
658 if ( fp )
659 {
660 Print( fp, 0 );
661 fclose( fp );
662 return true;
663 }
664 return false;
665 }
666
667
Clone() const668 TiXmlNode* TiXmlDocument::Clone() const
669 {
670 TiXmlDocument* clone = new TiXmlDocument();
671 if ( !clone )
672 return 0;
673
674 CopyToClone( clone );
675 clone->error = error;
676 clone->errorDesc = errorDesc;
677
678 TiXmlNode* node = 0;
679 for ( node = firstChild; node; node = node->NextSibling() )
680 {
681 clone->LinkEndChild( node->Clone() );
682 }
683 return clone;
684 }
685
686
Print(FILE * cfile,int depth) const687 void TiXmlDocument::Print( FILE* cfile, int depth ) const
688 {
689 TiXmlNode* node;
690 for ( node=FirstChild(); node; node=node->NextSibling() )
691 {
692 node->Print( cfile, depth );
693 fprintf( cfile, "\n" );
694 }
695 }
696
697
StreamOut(std::ostream * out) const698 void TiXmlDocument::StreamOut( std::ostream* out ) const
699 {
700 TiXmlNode* node;
701 for ( node=FirstChild(); node; node=node->NextSibling() )
702 {
703 node->StreamOut( out );
704
705 // Special rule for streams: stop after the root element.
706 // The stream in code will only read one element, so don't
707 // write more than one.
708 if ( node->ToElement() )
709 break;
710 }
711 }
712
713
Next() const714 TiXmlAttribute* TiXmlAttribute::Next() const
715 {
716 // We are using knowledge of the sentinel. The sentinel
717 // have a value or name.
718 if ( next->value.empty() && next->name.empty() )
719 return 0;
720 return next;
721 }
722
723
Previous() const724 TiXmlAttribute* TiXmlAttribute::Previous() const
725 {
726 // We are using knowledge of the sentinel. The sentinel
727 // have a value or name.
728 if ( prev->value.empty() && prev->name.empty() )
729 return 0;
730 return prev;
731 }
732
733
Print(FILE * cfile,int) const734 void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const
735 {
736 ostringstream stream( ostringstream::out );
737 stream.str().reserve( 500 );
738
739 StreamOut( &stream );
740 fprintf( cfile, "%s", stream.str().c_str() );
741 }
742
743
StreamOut(std::ostream * stream) const744 void TiXmlAttribute::StreamOut( std::ostream* stream ) const
745 {
746 if ( value.find( '\"' ) != std::string::npos )
747 {
748 PutString( name, stream );
749 (*stream) << "=" << "'";
750 PutString( value, stream );
751 (*stream) << "'";
752 }
753 else
754 {
755 PutString( name, stream );
756 (*stream) << "=" << "\"";
757 PutString( value, stream );
758 (*stream) << "\"";
759 }
760 }
761
762
SetIntValue(int value)763 void TiXmlAttribute::SetIntValue( int value )
764 {
765 std::string s;
766 std::ostringstream stream( s );
767 stream << value;
768 SetValue( stream.str() );
769 }
770
771
SetDoubleValue(double value)772 void TiXmlAttribute::SetDoubleValue( double value )
773 {
774 std::string s;
775 std::ostringstream stream( s );
776 stream << value;
777 SetValue( stream.str() );
778 }
779
780
IntValue() const781 const int TiXmlAttribute::IntValue() const
782 {
783 int v;
784 std::istringstream string( value );
785 string >> v;
786 return v;
787 }
788
789
DoubleValue() const790 const double TiXmlAttribute::DoubleValue() const
791 {
792 double v;
793 std::istringstream string( value );
794 string >> v;
795 return v;
796 }
797
798
Print(FILE * cfile,int depth) const799 void TiXmlComment::Print( FILE* cfile, int depth ) const
800 {
801 ostringstream stream( ostringstream::out );
802 stream.str().reserve( 1000 );
803
804 for ( int i=0; i<depth; i++ )
805 {
806 fprintf( cfile, " " );
807 }
808 StreamOut( &stream );
809 fprintf( cfile, "%s", stream.str().c_str() );
810 }
811
812
StreamOut(std::ostream * stream) const813 void TiXmlComment::StreamOut( std::ostream* stream ) const
814 {
815 (*stream) << "<!--";
816 PutString( value, stream );
817 (*stream) << "-->";
818 }
819
820
Clone() const821 TiXmlNode* TiXmlComment::Clone() const
822 {
823 TiXmlComment* clone = new TiXmlComment();
824
825 if ( !clone )
826 return 0;
827
828 CopyToClone( clone );
829 return clone;
830 }
831
832
Print(FILE * cfile,int depth) const833 void TiXmlText::Print( FILE* cfile, int depth ) const
834 {
835 ostringstream stream( ostringstream::out );
836 stream.str().reserve( 1000 );
837 StreamOut( &stream );
838 fprintf( cfile, "%s", stream.str().c_str() );
839 }
840
841
StreamOut(std::ostream * stream) const842 void TiXmlText::StreamOut( std::ostream* stream ) const
843 {
844 PutString( value, stream );
845 }
846
847
Clone() const848 TiXmlNode* TiXmlText::Clone() const
849 {
850 TiXmlText* clone = 0;
851 clone = new TiXmlText( "" );
852
853 if ( !clone )
854 return 0;
855
856 CopyToClone( clone );
857 return clone;
858 }
859
860
TiXmlDeclaration(const std::string & _version,const std::string & _encoding,const std::string & _standalone)861 TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
862 const std::string& _encoding,
863 const std::string& _standalone )
864 : TiXmlNode( TiXmlNode::DECLARATION )
865 {
866 version = _version;
867 encoding = _encoding;
868 standalone = _standalone;
869 }
870
871
Print(FILE * cfile,int depth) const872 void TiXmlDeclaration::Print( FILE* cfile, int depth ) const
873 {
874 ostringstream stream( ostringstream::out );
875 stream.str().reserve( 200 );
876 StreamOut( &stream );
877 fprintf( cfile, "%s", stream.str().c_str() );
878 }
879
880
StreamOut(std::ostream * stream) const881 void TiXmlDeclaration::StreamOut( std::ostream* stream ) const
882 {
883 (*stream) << "<?xml ";
884
885 if ( !version.empty() )
886 {
887 (*stream) << "version=\"";
888 PutString( version, stream );
889 (*stream) << "\" ";
890 }
891 if ( !encoding.empty() )
892 {
893 (*stream) << "encoding=\"";
894 PutString( encoding, stream );
895 (*stream ) << "\" ";
896 }
897 if ( !standalone.empty() )
898 {
899 (*stream) << "standalone=\"";
900 PutString( standalone, stream );
901 (*stream) << "\" ";
902 }
903 (*stream) << "?>";
904 }
905
906
Clone() const907 TiXmlNode* TiXmlDeclaration::Clone() const
908 {
909 TiXmlDeclaration* clone = new TiXmlDeclaration();
910
911 if ( !clone )
912 return 0;
913
914 CopyToClone( clone );
915 clone->version = version;
916 clone->encoding = encoding;
917 clone->standalone = standalone;
918 return clone;
919 }
920
921
Print(FILE * cfile,int depth) const922 void TiXmlUnknown::Print( FILE* cfile, int depth ) const
923 {
924 ostringstream stream( ostringstream::out );
925 stream.str().reserve( 200 );
926 StreamOut( &stream );
927
928 for ( int i=0; i<depth; i++ )
929 fprintf( cfile, " " );
930 fprintf( cfile, "%s", stream.str().c_str() );
931 }
932
933
StreamOut(std::ostream * stream) const934 void TiXmlUnknown::StreamOut( std::ostream* stream ) const
935 {
936 (*stream) << "<" << value << ">"; // Don't use entities hear! It is unknown.
937 }
938
939
Clone() const940 TiXmlNode* TiXmlUnknown::Clone() const
941 {
942 TiXmlUnknown* clone = new TiXmlUnknown();
943
944 if ( !clone )
945 return 0;
946
947 CopyToClone( clone );
948 return clone;
949 }
950
951
TiXmlAttributeSet()952 TiXmlAttributeSet::TiXmlAttributeSet()
953 {
954 sentinel.next = &sentinel;
955 sentinel.prev = &sentinel;
956 }
957
958
~TiXmlAttributeSet()959 TiXmlAttributeSet::~TiXmlAttributeSet()
960 {
961 assert( sentinel.next == &sentinel );
962 assert( sentinel.prev == &sentinel );
963 }
964
965
Add(TiXmlAttribute * addMe)966 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
967 {
968 assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
969
970 addMe->next = &sentinel;
971 addMe->prev = sentinel.prev;
972
973 sentinel.prev->next = addMe;
974 sentinel.prev = addMe;
975 }
976
Remove(TiXmlAttribute * removeMe)977 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
978 {
979 TiXmlAttribute* node;
980
981 for( node = sentinel.next; node != &sentinel; node = node->next )
982 {
983 if ( node == removeMe )
984 {
985 node->prev->next = node->next;
986 node->next->prev = node->prev;
987 node->next = 0;
988 node->prev = 0;
989 return;
990 }
991 }
992 assert( 0 ); // we tried to remove a non-linked attribute.
993 }
994
995
Find(const std::string & name) const996 TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
997 {
998 TiXmlAttribute* node;
999
1000 for( node = sentinel.next; node != &sentinel; node = node->next )
1001 {
1002 if ( node->Name() == name )
1003 return node;
1004 }
1005 return 0;
1006 }
1007
1008