1 /*
2 www.sourceforge.net/projects/tinyxml
3 Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
4 
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12 
13 1. The origin of this software must not be misrepresented; you must
14 not claim that you wrote the original software. If you use this
15 software in a product, an acknowledgment in the product documentation
16 would be appreciated but is not required.
17 
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20 
21 3. This notice may not be removed or altered from any source
22 distribution.
23 */
24 
25 #include <ctype.h>
26 #include "tinyxml.h"
27 
28 #ifdef TIXML_USE_STL
29 #include <sstream>
30 #endif
31 
32 
33 bool TiXmlBase::condenseWhiteSpace = true;
34 
PutString(const TIXML_STRING & str,TIXML_OSTREAM * stream)35 void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream )
36 {
37 	TIXML_STRING buffer;
38 	PutString( str, &buffer );
39 	(*stream) << buffer;
40 }
41 
PutString(const TIXML_STRING & str,TIXML_STRING * outString)42 void 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 			sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
104 			//*ME:	warning C4267: convert 'size_t' to 'int'
105 			//*ME:	Int-Cast to make compiler happy ...
106 			outString->append( buf, (int)strlen( buf ) );
107 			++i;
108 		}
109 		else
110 		{
111 			//char realc = (char) c;
112 			//outString->append( &realc, 1 );
113 			*outString += (char) c;	// somewhat more efficient function call.
114 			++i;
115 		}
116 	}
117 }
118 
119 
120 // <-- Strange class for a bug fix. Search for STL_STRING_BUG
StringToBuffer(const TIXML_STRING & str)121 TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str )
122 {
123 	buffer = new char[ str.length()+1 ];
124 	if ( buffer )
125 	{
126 		strcpy( buffer, str.c_str() );
127 	}
128 }
129 
130 
~StringToBuffer()131 TiXmlBase::StringToBuffer::~StringToBuffer()
132 {
133 	delete [] buffer;
134 }
135 // End strange bug fix. -->
136 
137 
TiXmlNode(NodeType _type)138 TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
139 {
140 	parent = 0;
141 	type = _type;
142 	firstChild = 0;
143 	lastChild = 0;
144 	prev = 0;
145 	next = 0;
146 }
147 
148 
~TiXmlNode()149 TiXmlNode::~TiXmlNode()
150 {
151 	TiXmlNode* node = firstChild;
152 	TiXmlNode* temp = 0;
153 
154 	while ( node )
155 	{
156 		temp = node;
157 		node = node->next;
158 		delete temp;
159 	}
160 }
161 
162 
CopyTo(TiXmlNode * target) const163 void TiXmlNode::CopyTo( TiXmlNode* target ) const
164 {
165 	target->SetValue (value.c_str() );
166 	target->userData = userData;
167 }
168 
169 
Clear()170 void TiXmlNode::Clear()
171 {
172 	TiXmlNode* node = firstChild;
173 	TiXmlNode* temp = 0;
174 
175 	while ( node )
176 	{
177 		temp = node;
178 		node = node->next;
179 		delete temp;
180 	}
181 
182 	firstChild = 0;
183 	lastChild = 0;
184 }
185 
186 
LinkEndChild(TiXmlNode * node)187 TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
188 {
189 	node->parent = this;
190 
191 	node->prev = lastChild;
192 	node->next = 0;
193 
194 	if ( lastChild )
195 		lastChild->next = node;
196 	else
197 		firstChild = node;			// it was an empty list.
198 
199 	lastChild = node;
200 	return node;
201 }
202 
203 
InsertEndChild(const TiXmlNode & addThis)204 TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
205 {
206 	TiXmlNode* node = addThis.Clone();
207 	if ( !node )
208 		return 0;
209 
210 	return LinkEndChild( node );
211 }
212 
213 
InsertBeforeChild(TiXmlNode * beforeThis,const TiXmlNode & addThis)214 TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
215 {
216 	if ( !beforeThis || beforeThis->parent != this )
217 		return 0;
218 
219 	TiXmlNode* node = addThis.Clone();
220 	if ( !node )
221 		return 0;
222 	node->parent = this;
223 
224 	node->next = beforeThis;
225 	node->prev = beforeThis->prev;
226 	if ( beforeThis->prev )
227 	{
228 		beforeThis->prev->next = node;
229 	}
230 	else
231 	{
232 		assert( firstChild == beforeThis );
233 		firstChild = node;
234 	}
235 	beforeThis->prev = node;
236 	return node;
237 }
238 
239 
InsertAfterChild(TiXmlNode * afterThis,const TiXmlNode & addThis)240 TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
241 {
242 	if ( !afterThis || afterThis->parent != this )
243 		return 0;
244 
245 	TiXmlNode* node = addThis.Clone();
246 	if ( !node )
247 		return 0;
248 	node->parent = this;
249 
250 	node->prev = afterThis;
251 	node->next = afterThis->next;
252 	if ( afterThis->next )
253 	{
254 		afterThis->next->prev = node;
255 	}
256 	else
257 	{
258 		assert( lastChild == afterThis );
259 		lastChild = node;
260 	}
261 	afterThis->next = node;
262 	return node;
263 }
264 
265 
ReplaceChild(TiXmlNode * replaceThis,const TiXmlNode & withThis)266 TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
267 {
268 	if ( replaceThis->parent != this )
269 		return 0;
270 
271 	TiXmlNode* node = withThis.Clone();
272 	if ( !node )
273 		return 0;
274 
275 	node->next = replaceThis->next;
276 	node->prev = replaceThis->prev;
277 
278 	if ( replaceThis->next )
279 		replaceThis->next->prev = node;
280 	else
281 		lastChild = node;
282 
283 	if ( replaceThis->prev )
284 		replaceThis->prev->next = node;
285 	else
286 		firstChild = node;
287 
288 	delete replaceThis;
289 	node->parent = this;
290 	return node;
291 }
292 
293 
RemoveChild(TiXmlNode * removeThis)294 bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
295 {
296 	if ( removeThis->parent != this )
297 	{
298 		assert( 0 );
299 		return false;
300 	}
301 
302 	if ( removeThis->next )
303 		removeThis->next->prev = removeThis->prev;
304 	else
305 		lastChild = removeThis->prev;
306 
307 	if ( removeThis->prev )
308 		removeThis->prev->next = removeThis->next;
309 	else
310 		firstChild = removeThis->next;
311 
312 	delete removeThis;
313 	return true;
314 }
315 
FirstChild(const char * _value) const316 const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
317 {
318 	const TiXmlNode* node;
319 	for ( node = firstChild; node; node = node->next )
320 	{
321 		if ( node->SValue() == _value )
322 			return node;
323 	}
324 	return 0;
325 }
326 
327 
FirstChild(const char * _value)328 TiXmlNode* TiXmlNode::FirstChild( const char * _value )
329 {
330 	TiXmlNode* node;
331 	for ( node = firstChild; node; node = node->next )
332 	{
333 		if ( node->SValue() == _value )
334 			return node;
335 	}
336 	return 0;
337 }
338 
339 
LastChild(const char * _value) const340 const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
341 {
342 	const TiXmlNode* node;
343 	for ( node = lastChild; node; node = node->prev )
344 	{
345 		if ( node->SValue() == _value )
346 			return node;
347 	}
348 	return 0;
349 }
350 
LastChild(const char * _value)351 TiXmlNode* TiXmlNode::LastChild( const char * _value )
352 {
353 	TiXmlNode* node;
354 	for ( node = lastChild; node; node = node->prev )
355 	{
356 		if ( node->SValue() == _value )
357 			return node;
358 	}
359 	return 0;
360 }
361 
IterateChildren(const TiXmlNode * previous) const362 const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
363 {
364 	if ( !previous )
365 	{
366 		return FirstChild();
367 	}
368 	else
369 	{
370 		assert( previous->parent == this );
371 		return previous->NextSibling();
372 	}
373 }
374 
IterateChildren(TiXmlNode * previous)375 TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous )
376 {
377 	if ( !previous )
378 	{
379 		return FirstChild();
380 	}
381 	else
382 	{
383 		assert( previous->parent == this );
384 		return previous->NextSibling();
385 	}
386 }
387 
IterateChildren(const char * val,const TiXmlNode * previous) const388 const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
389 {
390 	if ( !previous )
391 	{
392 		return FirstChild( val );
393 	}
394 	else
395 	{
396 		assert( previous->parent == this );
397 		return previous->NextSibling( val );
398 	}
399 }
400 
IterateChildren(const char * val,TiXmlNode * previous)401 TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous )
402 {
403 	if ( !previous )
404 	{
405 		return FirstChild( val );
406 	}
407 	else
408 	{
409 		assert( previous->parent == this );
410 		return previous->NextSibling( val );
411 	}
412 }
413 
NextSibling(const char * _value) const414 const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
415 {
416 	const TiXmlNode* node;
417 	for ( node = next; node; node = node->next )
418 	{
419 		if ( node->SValue() == _value )
420 			return node;
421 	}
422 	return 0;
423 }
424 
NextSibling(const char * _value)425 TiXmlNode* TiXmlNode::NextSibling( const char * _value )
426 {
427 	TiXmlNode* node;
428 	for ( node = next; node; node = node->next )
429 	{
430 		if ( node->SValue() == _value )
431 			return node;
432 	}
433 	return 0;
434 }
435 
PreviousSibling(const char * _value) const436 const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
437 {
438 	const TiXmlNode* node;
439 	for ( node = prev; node; node = node->prev )
440 	{
441 		if ( node->SValue() == _value )
442 			return node;
443 	}
444 	return 0;
445 }
446 
PreviousSibling(const char * _value)447 TiXmlNode* TiXmlNode::PreviousSibling( const char * _value )
448 {
449 	TiXmlNode* node;
450 	for ( node = prev; node; node = node->prev )
451 	{
452 		if ( node->SValue() == _value )
453 			return node;
454 	}
455 	return 0;
456 }
457 
RemoveAttribute(const char * name)458 void TiXmlElement::RemoveAttribute( const char * name )
459 {
460 	TiXmlAttribute* node = attributeSet.Find( name );
461 	if ( node )
462 	{
463 		attributeSet.Remove( node );
464 		delete node;
465 	}
466 }
467 
FirstChildElement() const468 const TiXmlElement* TiXmlNode::FirstChildElement() const
469 {
470 	const TiXmlNode* node;
471 
472 	for (	node = FirstChild();
473 			node;
474 			node = node->NextSibling() )
475 	{
476 		if ( node->ToElement() )
477 			return node->ToElement();
478 	}
479 	return 0;
480 }
481 
FirstChildElement()482 TiXmlElement* TiXmlNode::FirstChildElement()
483 {
484 	TiXmlNode* node;
485 
486 	for (	node = FirstChild();
487 			node;
488 			node = node->NextSibling() )
489 	{
490 		if ( node->ToElement() )
491 			return node->ToElement();
492 	}
493 	return 0;
494 }
495 
FirstChildElement(const char * _value) const496 const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
497 {
498 	const TiXmlNode* node;
499 
500 	for (	node = FirstChild( _value );
501 			node;
502 			node = node->NextSibling( _value ) )
503 	{
504 		if ( node->ToElement() )
505 			return node->ToElement();
506 	}
507 	return 0;
508 }
509 
FirstChildElement(const char * _value)510 TiXmlElement* TiXmlNode::FirstChildElement( const char * _value )
511 {
512 	TiXmlNode* node;
513 
514 	for (	node = FirstChild( _value );
515 			node;
516 			node = node->NextSibling( _value ) )
517 	{
518 		if ( node->ToElement() )
519 			return node->ToElement();
520 	}
521 	return 0;
522 }
523 
NextSiblingElement() const524 const TiXmlElement* TiXmlNode::NextSiblingElement() const
525 {
526 	const TiXmlNode* node;
527 
528 	for (	node = NextSibling();
529 	node;
530 	node = node->NextSibling() )
531 	{
532 		if ( node->ToElement() )
533 			return node->ToElement();
534 	}
535 	return 0;
536 }
537 
NextSiblingElement()538 TiXmlElement* TiXmlNode::NextSiblingElement()
539 {
540 	TiXmlNode* node;
541 
542 	for (	node = NextSibling();
543 	node;
544 	node = node->NextSibling() )
545 	{
546 		if ( node->ToElement() )
547 			return node->ToElement();
548 	}
549 	return 0;
550 }
551 
NextSiblingElement(const char * _value) const552 const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
553 {
554 	const TiXmlNode* node;
555 
556 	for (	node = NextSibling( _value );
557 	node;
558 	node = node->NextSibling( _value ) )
559 	{
560 		if ( node->ToElement() )
561 			return node->ToElement();
562 	}
563 	return 0;
564 }
565 
NextSiblingElement(const char * _value)566 TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value )
567 {
568 	TiXmlNode* node;
569 
570 	for (	node = NextSibling( _value );
571 	node;
572 	node = node->NextSibling( _value ) )
573 	{
574 		if ( node->ToElement() )
575 			return node->ToElement();
576 	}
577 	return 0;
578 }
579 
580 
GetDocument() const581 const TiXmlDocument* TiXmlNode::GetDocument() const
582 {
583 	const TiXmlNode* node;
584 
585 	for( node = this; node; node = node->parent )
586 	{
587 		if ( node->ToDocument() )
588 			return node->ToDocument();
589 	}
590 	return 0;
591 }
592 
GetDocument()593 TiXmlDocument* TiXmlNode::GetDocument()
594 {
595 	TiXmlNode* node;
596 
597 	for( node = this; node; node = node->parent )
598 	{
599 		if ( node->ToDocument() )
600 			return node->ToDocument();
601 	}
602 	return 0;
603 }
604 
TiXmlElement(const char * _value)605 TiXmlElement::TiXmlElement (const char * _value)
606 	: TiXmlNode( TiXmlNode::ELEMENT )
607 {
608 	firstChild = lastChild = 0;
609 	value = _value;
610 }
611 
612 
613 #ifdef TIXML_USE_STL
TiXmlElement(const std::string & _value)614 TiXmlElement::TiXmlElement( const std::string& _value )
615 	: TiXmlNode( TiXmlNode::ELEMENT )
616 {
617 	firstChild = lastChild = 0;
618 	value = _value;
619 }
620 #endif
621 
622 
TiXmlElement(const TiXmlElement & copy)623 TiXmlElement::TiXmlElement( const TiXmlElement& copy)
624 	: TiXmlNode( TiXmlNode::ELEMENT )
625 {
626 	firstChild = lastChild = 0;
627 	copy.CopyTo( this );
628 }
629 
630 
operator =(const TiXmlElement & base)631 void TiXmlElement::operator=( const TiXmlElement& base )
632 {
633 	ClearThis();
634 	base.CopyTo( this );
635 }
636 
637 
~TiXmlElement()638 TiXmlElement::~TiXmlElement()
639 {
640 	ClearThis();
641 }
642 
643 
ClearThis()644 void TiXmlElement::ClearThis()
645 {
646 	Clear();
647 	while( attributeSet.First() )
648 	{
649 		TiXmlAttribute* node = attributeSet.First();
650 		attributeSet.Remove( node );
651 		delete node;
652 	}
653 }
654 
655 
Attribute(const char * name) const656 const char * TiXmlElement::Attribute( const char * name ) const
657 {
658 	const TiXmlAttribute* node = attributeSet.Find( name );
659 
660 	if ( node )
661 		return node->Value();
662 
663 	return 0;
664 }
665 
666 
Attribute(const char * name,int * i) const667 const char * TiXmlElement::Attribute( const char * name, int* i ) const
668 {
669 	const char * s = Attribute( name );
670 	if ( i )
671 	{
672 		if ( s )
673 			*i = atoi( s );
674 		else
675 			*i = 0;
676 	}
677 	return s;
678 }
679 
680 
Attribute(const char * name,double * d) const681 const char * TiXmlElement::Attribute( const char * name, double* d ) const
682 {
683 	const char * s = Attribute( name );
684 	if ( d )
685 	{
686 		if ( s )
687 			*d = atof( s );
688 		else
689 			*d = 0;
690 	}
691 	return s;
692 }
693 
694 
QueryIntAttribute(const char * name,int * ival) const695 int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
696 {
697 	const TiXmlAttribute* node = attributeSet.Find( name );
698 	if ( !node )
699 		return TIXML_NO_ATTRIBUTE;
700 
701 	return node->QueryIntValue( ival );
702 }
703 
704 
QueryDoubleAttribute(const char * name,double * dval) const705 int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
706 {
707 	const TiXmlAttribute* node = attributeSet.Find( name );
708 	if ( !node )
709 		return TIXML_NO_ATTRIBUTE;
710 
711 	return node->QueryDoubleValue( dval );
712 }
713 
714 
SetAttribute(const char * name,int val)715 void TiXmlElement::SetAttribute( const char * name, int val )
716 {
717 	char buf[64];
718 	sprintf( buf, "%d", val );
719 	SetAttribute( name, buf );
720 }
721 
722 
SetDoubleAttribute(const char * name,double val)723 void TiXmlElement::SetDoubleAttribute( const char * name, double val )
724 {
725 	char buf[256];
726 	sprintf( buf, "%f", val );
727 	SetAttribute( name, buf );
728 }
729 
730 
SetAttribute(const char * name,const char * _value)731 void TiXmlElement::SetAttribute( const char * name, const char * _value )
732 {
733 	TiXmlAttribute* node = attributeSet.Find( name );
734 	if ( node )
735 	{
736 		node->SetValue( _value );
737 		return;
738 	}
739 
740 	TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
741 	if ( attrib )
742 	{
743 		attributeSet.Add( attrib );
744 	}
745 	else
746 	{
747 		TiXmlDocument* document = GetDocument();
748 		if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
749 	}
750 }
751 
Print(FILE * cfile,int depth) const752 void TiXmlElement::Print( FILE* cfile, int depth ) const
753 {
754 	int i;
755 	for ( i=0; i<depth; i++ )
756 	{
757 		fprintf( cfile, "    " );
758 	}
759 
760 	fprintf( cfile, "<%s", value.c_str() );
761 
762 	const TiXmlAttribute* attrib;
763 	for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
764 	{
765 		fprintf( cfile, " " );
766 		attrib->Print( cfile, depth );
767 	}
768 
769 	// There are 3 different formatting approaches:
770 	// 1) An element without children is printed as a <foo /> node
771 	// 2) An element with only a text child is printed as <foo> text </foo>
772 	// 3) An element with children is printed on multiple lines.
773 	TiXmlNode* node;
774 	if ( !firstChild )
775 	{
776 		fprintf( cfile, " />" );
777 	}
778 	else if ( firstChild == lastChild && firstChild->ToText() )
779 	{
780 		fprintf( cfile, ">" );
781 		firstChild->Print( cfile, depth + 1 );
782 		fprintf( cfile, "</%s>", value.c_str() );
783 	}
784 	else
785 	{
786 		fprintf( cfile, ">" );
787 
788 		for ( node = firstChild; node; node=node->NextSibling() )
789 		{
790 			if ( !node->ToText() )
791 			{
792 				fprintf( cfile, "\n" );
793 			}
794 			node->Print( cfile, depth+1 );
795 		}
796 		fprintf( cfile, "\n" );
797 		for( i=0; i<depth; ++i )
798 		fprintf( cfile, "    " );
799 		fprintf( cfile, "</%s>", value.c_str() );
800 	}
801 }
802 
StreamOut(TIXML_OSTREAM * stream) const803 void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const
804 {
805 	(*stream) << "<" << value;
806 
807 	const TiXmlAttribute* attrib;
808 	for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
809 	{
810 		(*stream) << " ";
811 		attrib->StreamOut( stream );
812 	}
813 
814 	// If this node has children, give it a closing tag. Else
815 	// make it an empty tag.
816 	TiXmlNode* node;
817 	if ( firstChild )
818 	{
819 		(*stream) << ">";
820 
821 		for ( node = firstChild; node; node=node->NextSibling() )
822 		{
823 			node->StreamOut( stream );
824 		}
825 		(*stream) << "</" << value << ">";
826 	}
827 	else
828 	{
829 		(*stream) << " />";
830 	}
831 }
832 
833 
CopyTo(TiXmlElement * target) const834 void TiXmlElement::CopyTo( TiXmlElement* target ) const
835 {
836 	// superclass:
837 	TiXmlNode::CopyTo( target );
838 
839 	// Element class:
840 	// Clone the attributes, then clone the children.
841 	const TiXmlAttribute* attribute = 0;
842 	for(	attribute = attributeSet.First();
843 	attribute;
844 	attribute = attribute->Next() )
845 	{
846 		target->SetAttribute( attribute->Name(), attribute->Value() );
847 	}
848 
849 	TiXmlNode* node = 0;
850 	for ( node = firstChild; node; node = node->NextSibling() )
851 	{
852 		target->LinkEndChild( node->Clone() );
853 	}
854 }
855 
856 
Clone() const857 TiXmlNode* TiXmlElement::Clone() const
858 {
859 	TiXmlElement* clone = new TiXmlElement( Value() );
860 	if ( !clone )
861 		return 0;
862 
863 	CopyTo( clone );
864 	return clone;
865 }
866 
867 
TiXmlDocument()868 TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
869 {
870 	tabsize = 4;
871 	ClearError();
872 }
873 
TiXmlDocument(const char * documentName)874 TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
875 {
876 	tabsize = 4;
877 	value = documentName;
878 	ClearError();
879 }
880 
881 
882 #ifdef TIXML_USE_STL
TiXmlDocument(const std::string & documentName)883 TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
884 {
885 	tabsize = 4;
886     value = documentName;
887 	ClearError();
888 }
889 #endif
890 
891 
TiXmlDocument(const TiXmlDocument & copy)892 TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
893 {
894 	copy.CopyTo( this );
895 }
896 
897 
operator =(const TiXmlDocument & copy)898 void TiXmlDocument::operator=( const TiXmlDocument& copy )
899 {
900 	Clear();
901 	copy.CopyTo( this );
902 }
903 
904 
LoadFile(TiXmlEncoding encoding)905 bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
906 {
907 	// See STL_STRING_BUG below.
908 	StringToBuffer buf( value );
909 
910 	if ( buf.buffer && LoadFile( buf.buffer, encoding ) )
911 		return true;
912 
913 	return false;
914 }
915 
916 
SaveFile() const917 bool TiXmlDocument::SaveFile() const
918 {
919 	// See STL_STRING_BUG below.
920 	StringToBuffer buf( value );
921 
922 	if ( buf.buffer && SaveFile( buf.buffer ) )
923 		return true;
924 
925 	return false;
926 }
927 
LoadFile(const char * filename,TiXmlEncoding encoding)928 bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding )
929 {
930 	// Delete the existing data:
931 	Clear();
932 	location.Clear();
933 
934 	// There was a really terrifying little bug here. The code:
935 	//		value = filename
936 	// in the STL case, cause the assignment method of the std::string to
937 	// be called. What is strange, is that the std::string had the same
938 	// address as it's c_str() method, and so bad things happen. Looks
939 	// like a bug in the Microsoft STL implementation.
940 	// See STL_STRING_BUG above.
941 	// Fixed with the StringToBuffer class.
942 	value = filename;
943 
944 	FILE* file = fopen( value.c_str (), "r" );
945 
946 	if ( file )
947 	{
948 		// Get the file size, so we can pre-allocate the string. HUGE speed impact.
949 		long length = 0;
950 		fseek( file, 0, SEEK_END );
951 		length = ftell( file );
952 		fseek( file, 0, SEEK_SET );
953 
954 		// Strange case, but good to handle up front.
955 		if ( length == 0 )
956 		{
957 			fclose( file );
958 			return false;
959 		}
960 
961 		// If we have a file, assume it is all one big XML file, and read it in.
962 		// The document parser may decide the document ends sooner than the entire file, however.
963 		TIXML_STRING data;
964 		data.reserve( length );
965 
966 		const int BUF_SIZE = 2048;
967 		char buf[BUF_SIZE];
968 
969 		while( fgets( buf, BUF_SIZE, file ) )
970 		{
971 			data += buf;
972 		}
973 		fclose( file );
974 
975 		Parse( data.c_str(), 0, encoding );
976 
977 		if (  Error() )
978             return false;
979         else
980 			return true;
981 	}
982 	SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
983 	return false;
984 }
985 
SaveFile(const char * filename) const986 bool TiXmlDocument::SaveFile( const char * filename ) const
987 {
988 	// The old c stuff lives on...
989 	FILE* fp = fopen( filename, "w" );
990 	if ( fp )
991 	{
992 		Print( fp, 0 );
993 		fclose( fp );
994 		return true;
995 	}
996 	return false;
997 }
998 
999 
CopyTo(TiXmlDocument * target) const1000 void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
1001 {
1002 	TiXmlNode::CopyTo( target );
1003 
1004 	target->error = error;
1005 	target->errorDesc = errorDesc.c_str ();
1006 
1007 	TiXmlNode* node = 0;
1008 	for ( node = firstChild; node; node = node->NextSibling() )
1009 	{
1010 		target->LinkEndChild( node->Clone() );
1011 	}
1012 }
1013 
1014 
Clone() const1015 TiXmlNode* TiXmlDocument::Clone() const
1016 {
1017 	TiXmlDocument* clone = new TiXmlDocument();
1018 	if ( !clone )
1019 		return 0;
1020 
1021 	CopyTo( clone );
1022 	return clone;
1023 }
1024 
1025 
Print(FILE * cfile,int depth) const1026 void TiXmlDocument::Print( FILE* cfile, int depth ) const
1027 {
1028 	const TiXmlNode* node;
1029 	for ( node=FirstChild(); node; node=node->NextSibling() )
1030 	{
1031 		node->Print( cfile, depth );
1032 		fprintf( cfile, "\n" );
1033 	}
1034 }
1035 
StreamOut(TIXML_OSTREAM * out) const1036 void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const
1037 {
1038 	const TiXmlNode* node;
1039 	for ( node=FirstChild(); node; node=node->NextSibling() )
1040 	{
1041 		node->StreamOut( out );
1042 
1043 		// Special rule for streams: stop after the root element.
1044 		// The stream in code will only read one element, so don't
1045 		// write more than one.
1046 		if ( node->ToElement() )
1047 			break;
1048 	}
1049 }
1050 
1051 
Next() const1052 const TiXmlAttribute* TiXmlAttribute::Next() const
1053 {
1054 	// We are using knowledge of the sentinel. The sentinel
1055 	// have a value or name.
1056 	if ( next->value.empty() && next->name.empty() )
1057 		return 0;
1058 	return next;
1059 }
1060 
Next()1061 TiXmlAttribute* TiXmlAttribute::Next()
1062 {
1063 	// We are using knowledge of the sentinel. The sentinel
1064 	// have a value or name.
1065 	if ( next->value.empty() && next->name.empty() )
1066 		return 0;
1067 	return next;
1068 }
1069 
Previous() const1070 const TiXmlAttribute* TiXmlAttribute::Previous() const
1071 {
1072 	// We are using knowledge of the sentinel. The sentinel
1073 	// have a value or name.
1074 	if ( prev->value.empty() && prev->name.empty() )
1075 		return 0;
1076 	return prev;
1077 }
1078 
Previous()1079 TiXmlAttribute* TiXmlAttribute::Previous()
1080 {
1081 	// We are using knowledge of the sentinel. The sentinel
1082 	// have a value or name.
1083 	if ( prev->value.empty() && prev->name.empty() )
1084 		return 0;
1085 	return prev;
1086 }
1087 
Print(FILE * cfile,int) const1088 void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const
1089 {
1090 	TIXML_STRING n, v;
1091 
1092 	PutString( name, &n );
1093 	PutString( value, &v );
1094 
1095 	if (value.find ('\"') == TIXML_STRING::npos)
1096 		fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1097 	else
1098 		fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1099 }
1100 
1101 
StreamOut(TIXML_OSTREAM * stream) const1102 void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const
1103 {
1104 	if (value.find( '\"' ) != TIXML_STRING::npos)
1105 	{
1106 		PutString( name, stream );
1107 		(*stream) << "=" << "'";
1108 		PutString( value, stream );
1109 		(*stream) << "'";
1110 	}
1111 	else
1112 	{
1113 		PutString( name, stream );
1114 		(*stream) << "=" << "\"";
1115 		PutString( value, stream );
1116 		(*stream) << "\"";
1117 	}
1118 }
1119 
QueryIntValue(int * ival) const1120 int TiXmlAttribute::QueryIntValue( int* ival ) const
1121 {
1122 	if ( sscanf( value.c_str(), "%d", ival ) == 1 )
1123 		return TIXML_SUCCESS;
1124 	return TIXML_WRONG_TYPE;
1125 }
1126 
QueryDoubleValue(double * dval) const1127 int TiXmlAttribute::QueryDoubleValue( double* dval ) const
1128 {
1129 	if ( sscanf( value.c_str(), "%lf", dval ) == 1 )
1130 		return TIXML_SUCCESS;
1131 	return TIXML_WRONG_TYPE;
1132 }
1133 
SetIntValue(int _value)1134 void TiXmlAttribute::SetIntValue( int _value )
1135 {
1136 	char buf [64];
1137 	sprintf (buf, "%d", _value);
1138 	SetValue (buf);
1139 }
1140 
SetDoubleValue(double _value)1141 void TiXmlAttribute::SetDoubleValue( double _value )
1142 {
1143 	char buf [256];
1144 	sprintf (buf, "%lf", _value);
1145 	SetValue (buf);
1146 }
1147 
IntValue() const1148 const int TiXmlAttribute::IntValue() const
1149 {
1150 	return atoi (value.c_str ());
1151 }
1152 
DoubleValue() const1153 const double  TiXmlAttribute::DoubleValue() const
1154 {
1155 	return atof (value.c_str ());
1156 }
1157 
1158 
TiXmlComment(const TiXmlComment & copy)1159 TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
1160 {
1161 	copy.CopyTo( this );
1162 }
1163 
1164 
operator =(const TiXmlComment & base)1165 void TiXmlComment::operator=( const TiXmlComment& base )
1166 {
1167 	Clear();
1168 	base.CopyTo( this );
1169 }
1170 
1171 
Print(FILE * cfile,int depth) const1172 void TiXmlComment::Print( FILE* cfile, int depth ) const
1173 {
1174 	for ( int i=0; i<depth; i++ )
1175 	{
1176 		fputs( "    ", cfile );
1177 	}
1178 	fprintf( cfile, "<!--%s-->", value.c_str() );
1179 }
1180 
StreamOut(TIXML_OSTREAM * stream) const1181 void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const
1182 {
1183 	(*stream) << "<!--";
1184 	//PutString( value, stream );
1185 	(*stream) << value;
1186 	(*stream) << "-->";
1187 }
1188 
1189 
CopyTo(TiXmlComment * target) const1190 void TiXmlComment::CopyTo( TiXmlComment* target ) const
1191 {
1192 	TiXmlNode::CopyTo( target );
1193 }
1194 
1195 
Clone() const1196 TiXmlNode* TiXmlComment::Clone() const
1197 {
1198 	TiXmlComment* clone = new TiXmlComment();
1199 
1200 	if ( !clone )
1201 		return 0;
1202 
1203 	CopyTo( clone );
1204 	return clone;
1205 }
1206 
1207 
Print(FILE * cfile,int) const1208 void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const
1209 {
1210 	TIXML_STRING buffer;
1211 	PutString( value, &buffer );
1212 	fprintf( cfile, "%s", buffer.c_str() );
1213 }
1214 
1215 
StreamOut(TIXML_OSTREAM * stream) const1216 void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const
1217 {
1218 	PutString( value, stream );
1219 }
1220 
1221 
CopyTo(TiXmlText * target) const1222 void TiXmlText::CopyTo( TiXmlText* target ) const
1223 {
1224 	TiXmlNode::CopyTo( target );
1225 }
1226 
1227 
Clone() const1228 TiXmlNode* TiXmlText::Clone() const
1229 {
1230 	TiXmlText* clone = 0;
1231 	clone = new TiXmlText( "" );
1232 
1233 	if ( !clone )
1234 		return 0;
1235 
1236 	CopyTo( clone );
1237 	return clone;
1238 }
1239 
1240 
TiXmlDeclaration(const char * _version,const char * _encoding,const char * _standalone)1241 TiXmlDeclaration::TiXmlDeclaration( const char * _version,
1242 									const char * _encoding,
1243 									const char * _standalone )
1244 	: TiXmlNode( TiXmlNode::DECLARATION )
1245 {
1246 	version = _version;
1247 	encoding = _encoding;
1248 	standalone = _standalone;
1249 }
1250 
1251 
1252 #ifdef TIXML_USE_STL
TiXmlDeclaration(const std::string & _version,const std::string & _encoding,const std::string & _standalone)1253 TiXmlDeclaration::TiXmlDeclaration(	const std::string& _version,
1254 									const std::string& _encoding,
1255 									const std::string& _standalone )
1256 	: TiXmlNode( TiXmlNode::DECLARATION )
1257 {
1258 	version = _version;
1259 	encoding = _encoding;
1260 	standalone = _standalone;
1261 }
1262 #endif
1263 
1264 
TiXmlDeclaration(const TiXmlDeclaration & copy)1265 TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
1266 	: TiXmlNode( TiXmlNode::DECLARATION )
1267 {
1268 	copy.CopyTo( this );
1269 }
1270 
1271 
operator =(const TiXmlDeclaration & copy)1272 void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
1273 {
1274 	Clear();
1275 	copy.CopyTo( this );
1276 }
1277 
1278 
Print(FILE * cfile,int) const1279 void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const
1280 {
1281 	fprintf (cfile, "<?xml ");
1282 
1283 	if ( !version.empty() )
1284 		fprintf (cfile, "version=\"%s\" ", version.c_str ());
1285 	if ( !encoding.empty() )
1286 		fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
1287 	if ( !standalone.empty() )
1288 		fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
1289 	fprintf (cfile, "?>");
1290 }
1291 
StreamOut(TIXML_OSTREAM * stream) const1292 void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const
1293 {
1294 	(*stream) << "<?xml ";
1295 
1296 	if ( !version.empty() )
1297 	{
1298 		(*stream) << "version=\"";
1299 		PutString( version, stream );
1300 		(*stream) << "\" ";
1301 	}
1302 	if ( !encoding.empty() )
1303 	{
1304 		(*stream) << "encoding=\"";
1305 		PutString( encoding, stream );
1306 		(*stream ) << "\" ";
1307 	}
1308 	if ( !standalone.empty() )
1309 	{
1310 		(*stream) << "standalone=\"";
1311 		PutString( standalone, stream );
1312 		(*stream) << "\" ";
1313 	}
1314 	(*stream) << "?>";
1315 }
1316 
1317 
CopyTo(TiXmlDeclaration * target) const1318 void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
1319 {
1320 	TiXmlNode::CopyTo( target );
1321 
1322 	target->version = version;
1323 	target->encoding = encoding;
1324 	target->standalone = standalone;
1325 }
1326 
1327 
Clone() const1328 TiXmlNode* TiXmlDeclaration::Clone() const
1329 {
1330 	TiXmlDeclaration* clone = new TiXmlDeclaration();
1331 
1332 	if ( !clone )
1333 		return 0;
1334 
1335 	CopyTo( clone );
1336 	return clone;
1337 }
1338 
1339 
Print(FILE * cfile,int depth) const1340 void TiXmlUnknown::Print( FILE* cfile, int depth ) const
1341 {
1342 	for ( int i=0; i<depth; i++ )
1343 		fprintf( cfile, "    " );
1344 	fprintf( cfile, "<%s>", value.c_str() );
1345 }
1346 
1347 
StreamOut(TIXML_OSTREAM * stream) const1348 void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const
1349 {
1350 	(*stream) << "<" << value << ">";		// Don't use entities here! It is unknown.
1351 }
1352 
1353 
CopyTo(TiXmlUnknown * target) const1354 void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
1355 {
1356 	TiXmlNode::CopyTo( target );
1357 }
1358 
1359 
Clone() const1360 TiXmlNode* TiXmlUnknown::Clone() const
1361 {
1362 	TiXmlUnknown* clone = new TiXmlUnknown();
1363 
1364 	if ( !clone )
1365 		return 0;
1366 
1367 	CopyTo( clone );
1368 	return clone;
1369 }
1370 
1371 
TiXmlAttributeSet()1372 TiXmlAttributeSet::TiXmlAttributeSet()
1373 {
1374 	sentinel.next = &sentinel;
1375 	sentinel.prev = &sentinel;
1376 }
1377 
1378 
~TiXmlAttributeSet()1379 TiXmlAttributeSet::~TiXmlAttributeSet()
1380 {
1381 	assert( sentinel.next == &sentinel );
1382 	assert( sentinel.prev == &sentinel );
1383 }
1384 
1385 
Add(TiXmlAttribute * addMe)1386 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
1387 {
1388 	assert( !Find( addMe->Name() ) );	// Shouldn't be multiply adding to the set.
1389 
1390 	addMe->next = &sentinel;
1391 	addMe->prev = sentinel.prev;
1392 
1393 	sentinel.prev->next = addMe;
1394 	sentinel.prev      = addMe;
1395 }
1396 
Remove(TiXmlAttribute * removeMe)1397 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
1398 {
1399 	TiXmlAttribute* node;
1400 
1401 	for( node = sentinel.next; node != &sentinel; node = node->next )
1402 	{
1403 		if ( node == removeMe )
1404 		{
1405 			node->prev->next = node->next;
1406 			node->next->prev = node->prev;
1407 			node->next = 0;
1408 			node->prev = 0;
1409 			return;
1410 		}
1411 	}
1412 	assert( 0 );		// we tried to remove a non-linked attribute.
1413 }
1414 
Find(const char * name) const1415 const TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const
1416 {
1417 	const TiXmlAttribute* node;
1418 
1419 	for( node = sentinel.next; node != &sentinel; node = node->next )
1420 	{
1421 		if ( node->name == name )
1422 			return node;
1423 	}
1424 	return 0;
1425 }
1426 
Find(const char * name)1427 TiXmlAttribute*	TiXmlAttributeSet::Find( const char * name )
1428 {
1429 	TiXmlAttribute* node;
1430 
1431 	for( node = sentinel.next; node != &sentinel; node = node->next )
1432 	{
1433 		if ( node->name == name )
1434 			return node;
1435 	}
1436 	return 0;
1437 }
1438 
1439 #ifdef TIXML_USE_STL
operator >>(TIXML_ISTREAM & in,TiXmlNode & base)1440 TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base)
1441 {
1442 	TIXML_STRING tag;
1443 	tag.reserve( 8 * 1000 );
1444 	base.StreamIn( &in, &tag );
1445 
1446 	base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1447 	return in;
1448 }
1449 #endif
1450 
1451 
operator <<(TIXML_OSTREAM & out,const TiXmlNode & base)1452 TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base)
1453 {
1454 	base.StreamOut (& out);
1455 	return out;
1456 }
1457 
1458 
1459 #ifdef TIXML_USE_STL
operator <<(std::string & out,const TiXmlNode & base)1460 std::string & operator<< (std::string& out, const TiXmlNode& base )
1461 {
1462    std::ostringstream os_stream( std::ostringstream::out );
1463    base.StreamOut( &os_stream );
1464 
1465    out.append( os_stream.str() );
1466    return out;
1467 }
1468 #endif
1469 
1470 
FirstChild() const1471 TiXmlHandle TiXmlHandle::FirstChild() const
1472 {
1473 	if ( node )
1474 	{
1475 		TiXmlNode* child = node->FirstChild();
1476 		if ( child )
1477 			return TiXmlHandle( child );
1478 	}
1479 	return TiXmlHandle( 0 );
1480 }
1481 
1482 
FirstChild(const char * value) const1483 TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
1484 {
1485 	if ( node )
1486 	{
1487 		TiXmlNode* child = node->FirstChild( value );
1488 		if ( child )
1489 			return TiXmlHandle( child );
1490 	}
1491 	return TiXmlHandle( 0 );
1492 }
1493 
1494 
FirstChildElement() const1495 TiXmlHandle TiXmlHandle::FirstChildElement() const
1496 {
1497 	if ( node )
1498 	{
1499 		TiXmlElement* child = node->FirstChildElement();
1500 		if ( child )
1501 			return TiXmlHandle( child );
1502 	}
1503 	return TiXmlHandle( 0 );
1504 }
1505 
1506 
FirstChildElement(const char * value) const1507 TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
1508 {
1509 	if ( node )
1510 	{
1511 		TiXmlElement* child = node->FirstChildElement( value );
1512 		if ( child )
1513 			return TiXmlHandle( child );
1514 	}
1515 	return TiXmlHandle( 0 );
1516 }
1517 
1518 
Child(int count) const1519 TiXmlHandle TiXmlHandle::Child( int count ) const
1520 {
1521 	if ( node )
1522 	{
1523 		int i;
1524 		TiXmlNode* child = node->FirstChild();
1525 		for (	i=0;
1526 				child && i<count;
1527 				child = child->NextSibling(), ++i )
1528 		{
1529 			// nothing
1530 		}
1531 		if ( child )
1532 			return TiXmlHandle( child );
1533 	}
1534 	return TiXmlHandle( 0 );
1535 }
1536 
1537 
Child(const char * value,int count) const1538 TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
1539 {
1540 	if ( node )
1541 	{
1542 		int i;
1543 		TiXmlNode* child = node->FirstChild( value );
1544 		for (	i=0;
1545 				child && i<count;
1546 				child = child->NextSibling( value ), ++i )
1547 		{
1548 			// nothing
1549 		}
1550 		if ( child )
1551 			return TiXmlHandle( child );
1552 	}
1553 	return TiXmlHandle( 0 );
1554 }
1555 
1556 
ChildElement(int count) const1557 TiXmlHandle TiXmlHandle::ChildElement( int count ) const
1558 {
1559 	if ( node )
1560 	{
1561 		int i;
1562 		TiXmlElement* child = node->FirstChildElement();
1563 		for (	i=0;
1564 				child && i<count;
1565 				child = child->NextSiblingElement(), ++i )
1566 		{
1567 			// nothing
1568 		}
1569 		if ( child )
1570 			return TiXmlHandle( child );
1571 	}
1572 	return TiXmlHandle( 0 );
1573 }
1574 
1575 
ChildElement(const char * value,int count) const1576 TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
1577 {
1578 	if ( node )
1579 	{
1580 		int i;
1581 		TiXmlElement* child = node->FirstChildElement( value );
1582 		for (	i=0;
1583 				child && i<count;
1584 				child = child->NextSiblingElement( value ), ++i )
1585 		{
1586 			// nothing
1587 		}
1588 		if ( child )
1589 			return TiXmlHandle( child );
1590 	}
1591 	return TiXmlHandle( 0 );
1592 }
1593