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