xref: /third_party/lame/ACM/tinyxml/tinyxml.cpp (revision 159b3361)
1/*
2Copyright (c) 2000 Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
23
24#include <iostream>
25#include <sstream>
26#include <fstream>
27#include "tinyxml.h"
28using namespace std;
29
30
31bool TiXmlBase::condenseWhiteSpace = true;
32
33
34void 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
82TiXmlNode::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
93TiXmlNode::~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
107void 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
124TiXmlNode* 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
141TiXmlNode* 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
151TiXmlNode* 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
169TiXmlNode* 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
187TiXmlNode* 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
215bool 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
238TiXmlNode* 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
250TiXmlNode* 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
262TiXmlNode* 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
276TiXmlNode* 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
290TiXmlNode* 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
302TiXmlNode* 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
314void 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
325TiXmlElement* 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
340TiXmlElement* 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
355TiXmlElement* 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
370TiXmlElement* 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
386TiXmlDocument* 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
404TiXmlElement::TiXmlElement( const std::string& _value )
405	: TiXmlNode( TiXmlNode::ELEMENT )
406{
407	firstChild = lastChild = 0;
408	value = _value;
409}
410
411TiXmlElement::~TiXmlElement()
412{
413	while( attributeSet.First() )
414	{
415		TiXmlAttribute* node = attributeSet.First();
416		attributeSet.Remove( node );
417		delete node;
418	}
419}
420
421const 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
432const 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
443void 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
454void 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
476void 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
528void 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
559TiXmlNode* 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
586TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
587{
588	error = false;
589//	ignoreWhiteSpace = true;
590}
591
592
593TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
594{
595//	ignoreWhiteSpace = true;
596	value = documentName;
597	error = false;
598}
599
600
601bool TiXmlDocument::LoadFile()
602{
603	return LoadFile( value );
604}
605
606
607bool TiXmlDocument::SaveFile() const
608{
609 	return SaveFile( value );
610}
611
612
613bool 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
654bool 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
668TiXmlNode* 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
687void 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
698void 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
714TiXmlAttribute* 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
724TiXmlAttribute* 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
734void 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
744void 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
763void TiXmlAttribute::SetIntValue( int value )
764{
765	std::string s;
766	std::ostringstream stream( s );
767	stream << value;
768	SetValue( stream.str() );
769}
770
771
772void TiXmlAttribute::SetDoubleValue( double value )
773{
774	std::string s;
775	std::ostringstream stream( s );
776	stream << value;
777	SetValue( stream.str() );
778}
779
780
781const int TiXmlAttribute::IntValue() const
782{
783	int v;
784	std::istringstream string( value );
785	string >> v;
786	return v;
787}
788
789
790const double  TiXmlAttribute::DoubleValue() const
791{
792	double v;
793	std::istringstream string( value );
794	string >> v;
795	return v;
796}
797
798
799void 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
813void TiXmlComment::StreamOut( std::ostream* stream ) const
814{
815	(*stream) << "<!--";
816	PutString( value, stream );
817	(*stream) << "-->";
818}
819
820
821TiXmlNode* 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
833void 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
842void TiXmlText::StreamOut( std::ostream* stream ) const
843{
844	PutString( value, stream );
845}
846
847
848TiXmlNode* 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
861TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
862									const std::string& _encoding,
863									const std::string& _standalone )
864	: TiXmlNode( TiXmlNode::DECLARATION )
865	, version( _version )
866	, encoding( _encoding )
867	, standalone( _standalone )
868{
869}
870
871
872void 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
881void 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
907TiXmlNode* 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
922void 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
934void TiXmlUnknown::StreamOut( std::ostream* stream ) const
935{
936	(*stream) << "<" << value << ">";		// Don't use entities hear! It is unknown.
937}
938
939
940TiXmlNode* 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
952TiXmlAttributeSet::TiXmlAttributeSet()
953{
954	sentinel.next = &sentinel;
955	sentinel.prev = &sentinel;
956}
957
958
959TiXmlAttributeSet::~TiXmlAttributeSet()
960{
961	assert( sentinel.next == &sentinel );
962	assert( sentinel.prev == &sentinel );
963}
964
965
966void 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
977void 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
996TiXmlAttribute*	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