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