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 // © -- 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