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