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