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