tinyxml2.cpp (76992B)
1 /* 2 Original code by Lee Thomason (www.grinninglizard.com) 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any 6 damages arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any 9 purpose, including commercial applications, and to alter it and 10 redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must 13 not claim that you wrote the original software. If you use this 14 software in a product, an acknowledgment in the product documentation 15 would be appreciated but is not required. 16 17 2. Altered source versions must be plainly marked as such, and 18 must not be misrepresented as being the original software. 19 20 3. This notice may not be removed or altered from any source 21 distribution. 22 */ 23 24 #include "tinyxml2.h" 25 26 #include <new> // yes, this one new style header, is in the Android SDK. 27 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) 28 # include <stddef.h> 29 # include <stdarg.h> 30 #else 31 # include <cstddef> 32 # include <cstdarg> 33 #endif 34 35 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) 36 // Microsoft Visual Studio, version 2005 and higher. Not WinCE. 37 /*int _snprintf_s( 38 char *buffer, 39 size_t sizeOfBuffer, 40 size_t count, 41 const char *format [, 42 argument] ... 43 );*/ 44 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) 45 { 46 va_list va; 47 va_start( va, format ); 48 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); 49 va_end( va ); 50 return result; 51 } 52 53 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) 54 { 55 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); 56 return result; 57 } 58 59 #define TIXML_VSCPRINTF _vscprintf 60 #define TIXML_SSCANF sscanf_s 61 #elif defined _MSC_VER 62 // Microsoft Visual Studio 2003 and earlier or WinCE 63 #define TIXML_SNPRINTF _snprintf 64 #define TIXML_VSNPRINTF _vsnprintf 65 #define TIXML_SSCANF sscanf 66 #if (_MSC_VER < 1400 ) && (!defined WINCE) 67 // Microsoft Visual Studio 2003 and not WinCE. 68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. 69 #else 70 // Microsoft Visual Studio 2003 and earlier or WinCE. 71 static inline int TIXML_VSCPRINTF( const char* format, va_list va ) 72 { 73 int len = 512; 74 for (;;) { 75 len = len*2; 76 char* str = new char[len](); 77 const int required = _vsnprintf(str, len, format, va); 78 delete[] str; 79 if ( required != -1 ) { 80 TIXMLASSERT( required >= 0 ); 81 len = required; 82 break; 83 } 84 } 85 TIXMLASSERT( len >= 0 ); 86 return len; 87 } 88 #endif 89 #else 90 // GCC version 3 and higher 91 //#warning( "Using sn* functions." ) 92 #define TIXML_SNPRINTF snprintf 93 #define TIXML_VSNPRINTF vsnprintf 94 static inline int TIXML_VSCPRINTF( const char* format, va_list va ) 95 { 96 int len = vsnprintf( 0, 0, format, va ); 97 TIXMLASSERT( len >= 0 ); 98 return len; 99 } 100 #define TIXML_SSCANF sscanf 101 #endif 102 103 104 static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF 105 static const char LF = LINE_FEED; 106 static const char CARRIAGE_RETURN = static_cast<char>(0x0d); // CR gets filtered out 107 static const char CR = CARRIAGE_RETURN; 108 static const char SINGLE_QUOTE = '\''; 109 static const char DOUBLE_QUOTE = '\"'; 110 111 // Bunch of unicode info at: 112 // http://www.unicode.org/faq/utf_bom.html 113 // ef bb bf (Microsoft "lead bytes") - designates UTF-8 114 115 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 116 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 117 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 118 119 namespace tinyxml2 120 { 121 122 struct Entity { 123 const char* pattern; 124 int length; 125 char value; 126 }; 127 128 static const int NUM_ENTITIES = 5; 129 static const Entity entities[NUM_ENTITIES] = { 130 { "quot", 4, DOUBLE_QUOTE }, 131 { "amp", 3, '&' }, 132 { "apos", 4, SINGLE_QUOTE }, 133 { "lt", 2, '<' }, 134 { "gt", 2, '>' } 135 }; 136 137 138 StrPair::~StrPair() 139 { 140 Reset(); 141 } 142 143 144 void StrPair::TransferTo( StrPair* other ) 145 { 146 if ( this == other ) { 147 return; 148 } 149 // This in effect implements the assignment operator by "moving" 150 // ownership (as in auto_ptr). 151 152 TIXMLASSERT( other != 0 ); 153 TIXMLASSERT( other->_flags == 0 ); 154 TIXMLASSERT( other->_start == 0 ); 155 TIXMLASSERT( other->_end == 0 ); 156 157 other->Reset(); 158 159 other->_flags = _flags; 160 other->_start = _start; 161 other->_end = _end; 162 163 _flags = 0; 164 _start = 0; 165 _end = 0; 166 } 167 168 169 void StrPair::Reset() 170 { 171 if ( _flags & NEEDS_DELETE ) { 172 delete [] _start; 173 } 174 _flags = 0; 175 _start = 0; 176 _end = 0; 177 } 178 179 180 void StrPair::SetStr( const char* str, int flags ) 181 { 182 TIXMLASSERT( str ); 183 Reset(); 184 size_t len = strlen( str ); 185 TIXMLASSERT( _start == 0 ); 186 _start = new char[ len+1 ]; 187 memcpy( _start, str, len+1 ); 188 _end = _start + len; 189 _flags = flags | NEEDS_DELETE; 190 } 191 192 193 char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) 194 { 195 TIXMLASSERT( p ); 196 TIXMLASSERT( endTag && *endTag ); 197 TIXMLASSERT(curLineNumPtr); 198 199 char* start = p; 200 const char endChar = *endTag; 201 size_t length = strlen( endTag ); 202 203 // Inner loop of text parsing. 204 while ( *p ) { 205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { 206 Set( start, p, strFlags ); 207 return p + length; 208 } else if (*p == '\n') { 209 ++(*curLineNumPtr); 210 } 211 ++p; 212 TIXMLASSERT( p ); 213 } 214 return 0; 215 } 216 217 218 char* StrPair::ParseName( char* p ) 219 { 220 if ( !p || !(*p) ) { 221 return 0; 222 } 223 if ( !XMLUtil::IsNameStartChar( *p ) ) { 224 return 0; 225 } 226 227 char* const start = p; 228 ++p; 229 while ( *p && XMLUtil::IsNameChar( *p ) ) { 230 ++p; 231 } 232 233 Set( start, p, 0 ); 234 return p; 235 } 236 237 238 void StrPair::CollapseWhitespace() 239 { 240 // Adjusting _start would cause undefined behavior on delete[] 241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); 242 // Trim leading space. 243 _start = XMLUtil::SkipWhiteSpace( _start, 0 ); 244 245 if ( *_start ) { 246 const char* p = _start; // the read pointer 247 char* q = _start; // the write pointer 248 249 while( *p ) { 250 if ( XMLUtil::IsWhiteSpace( *p )) { 251 p = XMLUtil::SkipWhiteSpace( p, 0 ); 252 if ( *p == 0 ) { 253 break; // don't write to q; this trims the trailing space. 254 } 255 *q = ' '; 256 ++q; 257 } 258 *q = *p; 259 ++q; 260 ++p; 261 } 262 *q = 0; 263 } 264 } 265 266 267 const char* StrPair::GetStr() 268 { 269 TIXMLASSERT( _start ); 270 TIXMLASSERT( _end ); 271 if ( _flags & NEEDS_FLUSH ) { 272 *_end = 0; 273 _flags ^= NEEDS_FLUSH; 274 275 if ( _flags ) { 276 const char* p = _start; // the read pointer 277 char* q = _start; // the write pointer 278 279 while( p < _end ) { 280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { 281 // CR-LF pair becomes LF 282 // CR alone becomes LF 283 // LF-CR becomes LF 284 if ( *(p+1) == LF ) { 285 p += 2; 286 } 287 else { 288 ++p; 289 } 290 *q = LF; 291 ++q; 292 } 293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { 294 if ( *(p+1) == CR ) { 295 p += 2; 296 } 297 else { 298 ++p; 299 } 300 *q = LF; 301 ++q; 302 } 303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { 304 // Entities handled by tinyXML2: 305 // - special entities in the entity table [in/out] 306 // - numeric character reference [in] 307 // 中 or 中 308 309 if ( *(p+1) == '#' ) { 310 const int buflen = 10; 311 char buf[buflen] = { 0 }; 312 int len = 0; 313 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); 314 if ( adjusted == 0 ) { 315 *q = *p; 316 ++p; 317 ++q; 318 } 319 else { 320 TIXMLASSERT( 0 <= len && len <= buflen ); 321 TIXMLASSERT( q + len <= adjusted ); 322 p = adjusted; 323 memcpy( q, buf, len ); 324 q += len; 325 } 326 } 327 else { 328 bool entityFound = false; 329 for( int i = 0; i < NUM_ENTITIES; ++i ) { 330 const Entity& entity = entities[i]; 331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 332 && *( p + entity.length + 1 ) == ';' ) { 333 // Found an entity - convert. 334 *q = entity.value; 335 ++q; 336 p += entity.length + 2; 337 entityFound = true; 338 break; 339 } 340 } 341 if ( !entityFound ) { 342 // fixme: treat as error? 343 ++p; 344 ++q; 345 } 346 } 347 } 348 else { 349 *q = *p; 350 ++p; 351 ++q; 352 } 353 } 354 *q = 0; 355 } 356 // The loop below has plenty going on, and this 357 // is a less useful mode. Break it out. 358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { 359 CollapseWhitespace(); 360 } 361 _flags = (_flags & NEEDS_DELETE); 362 } 363 TIXMLASSERT( _start ); 364 return _start; 365 } 366 367 368 369 370 // --------- XMLUtil ----------- // 371 372 const char* XMLUtil::writeBoolTrue = "true"; 373 const char* XMLUtil::writeBoolFalse = "false"; 374 375 void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) 376 { 377 static const char* defTrue = "true"; 378 static const char* defFalse = "false"; 379 380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue; 381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse; 382 } 383 384 385 const char* XMLUtil::ReadBOM( const char* p, bool* bom ) 386 { 387 TIXMLASSERT( p ); 388 TIXMLASSERT( bom ); 389 *bom = false; 390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); 391 // Check for BOM: 392 if ( *(pu+0) == TIXML_UTF_LEAD_0 393 && *(pu+1) == TIXML_UTF_LEAD_1 394 && *(pu+2) == TIXML_UTF_LEAD_2 ) { 395 *bom = true; 396 p += 3; 397 } 398 TIXMLASSERT( p ); 399 return p; 400 } 401 402 403 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) 404 { 405 const unsigned long BYTE_MASK = 0xBF; 406 const unsigned long BYTE_MARK = 0x80; 407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 408 409 if (input < 0x80) { 410 *length = 1; 411 } 412 else if ( input < 0x800 ) { 413 *length = 2; 414 } 415 else if ( input < 0x10000 ) { 416 *length = 3; 417 } 418 else if ( input < 0x200000 ) { 419 *length = 4; 420 } 421 else { 422 *length = 0; // This code won't convert this correctly anyway. 423 return; 424 } 425 426 output += *length; 427 428 // Scary scary fall throughs are annotated with carefully designed comments 429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc 430 switch (*length) { 431 case 4: 432 --output; 433 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK); 434 input >>= 6; 435 //fall through 436 case 3: 437 --output; 438 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK); 439 input >>= 6; 440 //fall through 441 case 2: 442 --output; 443 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK); 444 input >>= 6; 445 //fall through 446 case 1: 447 --output; 448 *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]); 449 break; 450 default: 451 TIXMLASSERT( false ); 452 } 453 } 454 455 456 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) 457 { 458 // Presume an entity, and pull it out. 459 *length = 0; 460 461 if ( *(p+1) == '#' && *(p+2) ) { 462 unsigned long ucs = 0; 463 TIXMLASSERT( sizeof( ucs ) >= 4 ); 464 ptrdiff_t delta = 0; 465 unsigned mult = 1; 466 static const char SEMICOLON = ';'; 467 468 if ( *(p+2) == 'x' ) { 469 // Hexadecimal. 470 const char* q = p+3; 471 if ( !(*q) ) { 472 return 0; 473 } 474 475 q = strchr( q, SEMICOLON ); 476 477 if ( !q ) { 478 return 0; 479 } 480 TIXMLASSERT( *q == SEMICOLON ); 481 482 delta = q-p; 483 --q; 484 485 while ( *q != 'x' ) { 486 unsigned int digit = 0; 487 488 if ( *q >= '0' && *q <= '9' ) { 489 digit = *q - '0'; 490 } 491 else if ( *q >= 'a' && *q <= 'f' ) { 492 digit = *q - 'a' + 10; 493 } 494 else if ( *q >= 'A' && *q <= 'F' ) { 495 digit = *q - 'A' + 10; 496 } 497 else { 498 return 0; 499 } 500 TIXMLASSERT( digit < 16 ); 501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); 502 const unsigned int digitScaled = mult * digit; 503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); 504 ucs += digitScaled; 505 TIXMLASSERT( mult <= UINT_MAX / 16 ); 506 mult *= 16; 507 --q; 508 } 509 } 510 else { 511 // Decimal. 512 const char* q = p+2; 513 if ( !(*q) ) { 514 return 0; 515 } 516 517 q = strchr( q, SEMICOLON ); 518 519 if ( !q ) { 520 return 0; 521 } 522 TIXMLASSERT( *q == SEMICOLON ); 523 524 delta = q-p; 525 --q; 526 527 while ( *q != '#' ) { 528 if ( *q >= '0' && *q <= '9' ) { 529 const unsigned int digit = *q - '0'; 530 TIXMLASSERT( digit < 10 ); 531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); 532 const unsigned int digitScaled = mult * digit; 533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); 534 ucs += digitScaled; 535 } 536 else { 537 return 0; 538 } 539 TIXMLASSERT( mult <= UINT_MAX / 10 ); 540 mult *= 10; 541 --q; 542 } 543 } 544 // convert the UCS to UTF-8 545 ConvertUTF32ToUTF8( ucs, value, length ); 546 return p + delta + 1; 547 } 548 return p+1; 549 } 550 551 552 void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) 553 { 554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); 555 } 556 557 558 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) 559 { 560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); 561 } 562 563 564 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) 565 { 566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); 567 } 568 569 /* 570 ToStr() of a number is a very tricky topic. 571 https://github.com/leethomason/tinyxml2/issues/106 572 */ 573 void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) 574 { 575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); 576 } 577 578 579 void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) 580 { 581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); 582 } 583 584 585 void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) 586 { 587 // horrible syntax trick to make the compiler happy about %lld 588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v)); 589 } 590 591 void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) 592 { 593 // horrible syntax trick to make the compiler happy about %llu 594 TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); 595 } 596 597 bool XMLUtil::ToInt( const char* str, int* value ) 598 { 599 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { 600 return true; 601 } 602 return false; 603 } 604 605 bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) 606 { 607 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { 608 return true; 609 } 610 return false; 611 } 612 613 bool XMLUtil::ToBool( const char* str, bool* value ) 614 { 615 int ival = 0; 616 if ( ToInt( str, &ival )) { 617 *value = (ival==0) ? false : true; 618 return true; 619 } 620 static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; 621 static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; 622 623 for (int i = 0; TRUE_VALS[i]; ++i) { 624 if (StringEqual(str, TRUE_VALS[i])) { 625 *value = true; 626 return true; 627 } 628 } 629 for (int i = 0; FALSE_VALS[i]; ++i) { 630 if (StringEqual(str, FALSE_VALS[i])) { 631 *value = false; 632 return true; 633 } 634 } 635 return false; 636 } 637 638 639 bool XMLUtil::ToFloat( const char* str, float* value ) 640 { 641 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { 642 return true; 643 } 644 return false; 645 } 646 647 648 bool XMLUtil::ToDouble( const char* str, double* value ) 649 { 650 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { 651 return true; 652 } 653 return false; 654 } 655 656 657 bool XMLUtil::ToInt64(const char* str, int64_t* value) 658 { 659 long long v = 0; // horrible syntax trick to make the compiler happy about %lld 660 if (TIXML_SSCANF(str, "%lld", &v) == 1) { 661 *value = static_cast<int64_t>(v); 662 return true; 663 } 664 return false; 665 } 666 667 668 bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { 669 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu 670 if(TIXML_SSCANF(str, "%llu", &v) == 1) { 671 *value = (uint64_t)v; 672 return true; 673 } 674 return false; 675 } 676 677 678 char* XMLDocument::Identify( char* p, XMLNode** node ) 679 { 680 TIXMLASSERT( node ); 681 TIXMLASSERT( p ); 682 char* const start = p; 683 int const startLine = _parseCurLineNum; 684 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); 685 if( !*p ) { 686 *node = 0; 687 TIXMLASSERT( p ); 688 return p; 689 } 690 691 // These strings define the matching patterns: 692 static const char* xmlHeader = { "<?" }; 693 static const char* commentHeader = { "<!--" }; 694 static const char* cdataHeader = { "<![CDATA[" }; 695 static const char* dtdHeader = { "<!" }; 696 static const char* elementHeader = { "<" }; // and a header for everything else; check last. 697 698 static const int xmlHeaderLen = 2; 699 static const int commentHeaderLen = 4; 700 static const int cdataHeaderLen = 9; 701 static const int dtdHeaderLen = 2; 702 static const int elementHeaderLen = 1; 703 704 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool 705 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool 706 XMLNode* returnNode = 0; 707 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { 708 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool ); 709 returnNode->_parseLineNum = _parseCurLineNum; 710 p += xmlHeaderLen; 711 } 712 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { 713 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool ); 714 returnNode->_parseLineNum = _parseCurLineNum; 715 p += commentHeaderLen; 716 } 717 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { 718 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool ); 719 returnNode = text; 720 returnNode->_parseLineNum = _parseCurLineNum; 721 p += cdataHeaderLen; 722 text->SetCData( true ); 723 } 724 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { 725 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool ); 726 returnNode->_parseLineNum = _parseCurLineNum; 727 p += dtdHeaderLen; 728 } 729 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { 730 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool ); 731 returnNode->_parseLineNum = _parseCurLineNum; 732 p += elementHeaderLen; 733 } 734 else { 735 returnNode = CreateUnlinkedNode<XMLText>( _textPool ); 736 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character 737 p = start; // Back it up, all the text counts. 738 _parseCurLineNum = startLine; 739 } 740 741 TIXMLASSERT( returnNode ); 742 TIXMLASSERT( p ); 743 *node = returnNode; 744 return p; 745 } 746 747 748 bool XMLDocument::Accept( XMLVisitor* visitor ) const 749 { 750 TIXMLASSERT( visitor ); 751 if ( visitor->VisitEnter( *this ) ) { 752 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { 753 if ( !node->Accept( visitor ) ) { 754 break; 755 } 756 } 757 } 758 return visitor->VisitExit( *this ); 759 } 760 761 762 // --------- XMLNode ----------- // 763 764 XMLNode::XMLNode( XMLDocument* doc ) : 765 _document( doc ), 766 _parent( 0 ), 767 _value(), 768 _parseLineNum( 0 ), 769 _firstChild( 0 ), _lastChild( 0 ), 770 _prev( 0 ), _next( 0 ), 771 _userData( 0 ), 772 _memPool( 0 ) 773 { 774 } 775 776 777 XMLNode::~XMLNode() 778 { 779 DeleteChildren(); 780 if ( _parent ) { 781 _parent->Unlink( this ); 782 } 783 } 784 785 const char* XMLNode::Value() const 786 { 787 // Edge case: XMLDocuments don't have a Value. Return null. 788 if ( this->ToDocument() ) 789 return 0; 790 return _value.GetStr(); 791 } 792 793 void XMLNode::SetValue( const char* str, bool staticMem ) 794 { 795 if ( staticMem ) { 796 _value.SetInternedStr( str ); 797 } 798 else { 799 _value.SetStr( str ); 800 } 801 } 802 803 XMLNode* XMLNode::DeepClone(XMLDocument* target) const 804 { 805 XMLNode* clone = this->ShallowClone(target); 806 if (!clone) return 0; 807 808 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { 809 XMLNode* childClone = child->DeepClone(target); 810 TIXMLASSERT(childClone); 811 clone->InsertEndChild(childClone); 812 } 813 return clone; 814 } 815 816 void XMLNode::DeleteChildren() 817 { 818 while( _firstChild ) { 819 TIXMLASSERT( _lastChild ); 820 DeleteChild( _firstChild ); 821 } 822 _firstChild = _lastChild = 0; 823 } 824 825 826 void XMLNode::Unlink( XMLNode* child ) 827 { 828 TIXMLASSERT( child ); 829 TIXMLASSERT( child->_document == _document ); 830 TIXMLASSERT( child->_parent == this ); 831 if ( child == _firstChild ) { 832 _firstChild = _firstChild->_next; 833 } 834 if ( child == _lastChild ) { 835 _lastChild = _lastChild->_prev; 836 } 837 838 if ( child->_prev ) { 839 child->_prev->_next = child->_next; 840 } 841 if ( child->_next ) { 842 child->_next->_prev = child->_prev; 843 } 844 child->_next = 0; 845 child->_prev = 0; 846 child->_parent = 0; 847 } 848 849 850 void XMLNode::DeleteChild( XMLNode* node ) 851 { 852 TIXMLASSERT( node ); 853 TIXMLASSERT( node->_document == _document ); 854 TIXMLASSERT( node->_parent == this ); 855 Unlink( node ); 856 TIXMLASSERT(node->_prev == 0); 857 TIXMLASSERT(node->_next == 0); 858 TIXMLASSERT(node->_parent == 0); 859 DeleteNode( node ); 860 } 861 862 863 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) 864 { 865 TIXMLASSERT( addThis ); 866 if ( addThis->_document != _document ) { 867 TIXMLASSERT( false ); 868 return 0; 869 } 870 InsertChildPreamble( addThis ); 871 872 if ( _lastChild ) { 873 TIXMLASSERT( _firstChild ); 874 TIXMLASSERT( _lastChild->_next == 0 ); 875 _lastChild->_next = addThis; 876 addThis->_prev = _lastChild; 877 _lastChild = addThis; 878 879 addThis->_next = 0; 880 } 881 else { 882 TIXMLASSERT( _firstChild == 0 ); 883 _firstChild = _lastChild = addThis; 884 885 addThis->_prev = 0; 886 addThis->_next = 0; 887 } 888 addThis->_parent = this; 889 return addThis; 890 } 891 892 893 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) 894 { 895 TIXMLASSERT( addThis ); 896 if ( addThis->_document != _document ) { 897 TIXMLASSERT( false ); 898 return 0; 899 } 900 InsertChildPreamble( addThis ); 901 902 if ( _firstChild ) { 903 TIXMLASSERT( _lastChild ); 904 TIXMLASSERT( _firstChild->_prev == 0 ); 905 906 _firstChild->_prev = addThis; 907 addThis->_next = _firstChild; 908 _firstChild = addThis; 909 910 addThis->_prev = 0; 911 } 912 else { 913 TIXMLASSERT( _lastChild == 0 ); 914 _firstChild = _lastChild = addThis; 915 916 addThis->_prev = 0; 917 addThis->_next = 0; 918 } 919 addThis->_parent = this; 920 return addThis; 921 } 922 923 924 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) 925 { 926 TIXMLASSERT( addThis ); 927 if ( addThis->_document != _document ) { 928 TIXMLASSERT( false ); 929 return 0; 930 } 931 932 TIXMLASSERT( afterThis ); 933 934 if ( afterThis->_parent != this ) { 935 TIXMLASSERT( false ); 936 return 0; 937 } 938 if ( afterThis == addThis ) { 939 // Current state: BeforeThis -> AddThis -> OneAfterAddThis 940 // Now AddThis must disappear from it's location and then 941 // reappear between BeforeThis and OneAfterAddThis. 942 // So just leave it where it is. 943 return addThis; 944 } 945 946 if ( afterThis->_next == 0 ) { 947 // The last node or the only node. 948 return InsertEndChild( addThis ); 949 } 950 InsertChildPreamble( addThis ); 951 addThis->_prev = afterThis; 952 addThis->_next = afterThis->_next; 953 afterThis->_next->_prev = addThis; 954 afterThis->_next = addThis; 955 addThis->_parent = this; 956 return addThis; 957 } 958 959 960 961 962 const XMLElement* XMLNode::FirstChildElement( const char* name ) const 963 { 964 for( const XMLNode* node = _firstChild; node; node = node->_next ) { 965 const XMLElement* element = node->ToElementWithName( name ); 966 if ( element ) { 967 return element; 968 } 969 } 970 return 0; 971 } 972 973 974 const XMLElement* XMLNode::LastChildElement( const char* name ) const 975 { 976 for( const XMLNode* node = _lastChild; node; node = node->_prev ) { 977 const XMLElement* element = node->ToElementWithName( name ); 978 if ( element ) { 979 return element; 980 } 981 } 982 return 0; 983 } 984 985 986 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const 987 { 988 for( const XMLNode* node = _next; node; node = node->_next ) { 989 const XMLElement* element = node->ToElementWithName( name ); 990 if ( element ) { 991 return element; 992 } 993 } 994 return 0; 995 } 996 997 998 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const 999 { 1000 for( const XMLNode* node = _prev; node; node = node->_prev ) { 1001 const XMLElement* element = node->ToElementWithName( name ); 1002 if ( element ) { 1003 return element; 1004 } 1005 } 1006 return 0; 1007 } 1008 1009 1010 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) 1011 { 1012 // This is a recursive method, but thinking about it "at the current level" 1013 // it is a pretty simple flat list: 1014 // <foo/> 1015 // <!-- comment --> 1016 // 1017 // With a special case: 1018 // <foo> 1019 // </foo> 1020 // <!-- comment --> 1021 // 1022 // Where the closing element (/foo) *must* be the next thing after the opening 1023 // element, and the names must match. BUT the tricky bit is that the closing 1024 // element will be read by the child. 1025 // 1026 // 'endTag' is the end tag for this node, it is returned by a call to a child. 1027 // 'parentEnd' is the end tag for the parent, which is filled in and returned. 1028 1029 XMLDocument::DepthTracker tracker(_document); 1030 if (_document->Error()) 1031 return 0; 1032 1033 while( p && *p ) { 1034 XMLNode* node = 0; 1035 1036 p = _document->Identify( p, &node ); 1037 TIXMLASSERT( p ); 1038 if ( node == 0 ) { 1039 break; 1040 } 1041 1042 const int initialLineNum = node->_parseLineNum; 1043 1044 StrPair endTag; 1045 p = node->ParseDeep( p, &endTag, curLineNumPtr ); 1046 if ( !p ) { 1047 DeleteNode( node ); 1048 if ( !_document->Error() ) { 1049 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); 1050 } 1051 break; 1052 } 1053 1054 const XMLDeclaration* const decl = node->ToDeclaration(); 1055 if ( decl ) { 1056 // Declarations are only allowed at document level 1057 // 1058 // Multiple declarations are allowed but all declarations 1059 // must occur before anything else. 1060 // 1061 // Optimized due to a security test case. If the first node is 1062 // a declaration, and the last node is a declaration, then only 1063 // declarations have so far been added. 1064 bool wellLocated = false; 1065 1066 if (ToDocument()) { 1067 if (FirstChild()) { 1068 wellLocated = 1069 FirstChild() && 1070 FirstChild()->ToDeclaration() && 1071 LastChild() && 1072 LastChild()->ToDeclaration(); 1073 } 1074 else { 1075 wellLocated = true; 1076 } 1077 } 1078 if ( !wellLocated ) { 1079 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); 1080 DeleteNode( node ); 1081 break; 1082 } 1083 } 1084 1085 XMLElement* ele = node->ToElement(); 1086 if ( ele ) { 1087 // We read the end tag. Return it to the parent. 1088 if ( ele->ClosingType() == XMLElement::CLOSING ) { 1089 if ( parentEndTag ) { 1090 ele->_value.TransferTo( parentEndTag ); 1091 } 1092 node->_memPool->SetTracked(); // created and then immediately deleted. 1093 DeleteNode( node ); 1094 return p; 1095 } 1096 1097 // Handle an end tag returned to this level. 1098 // And handle a bunch of annoying errors. 1099 bool mismatch = false; 1100 if ( endTag.Empty() ) { 1101 if ( ele->ClosingType() == XMLElement::OPEN ) { 1102 mismatch = true; 1103 } 1104 } 1105 else { 1106 if ( ele->ClosingType() != XMLElement::OPEN ) { 1107 mismatch = true; 1108 } 1109 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { 1110 mismatch = true; 1111 } 1112 } 1113 if ( mismatch ) { 1114 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); 1115 DeleteNode( node ); 1116 break; 1117 } 1118 } 1119 InsertEndChild( node ); 1120 } 1121 return 0; 1122 } 1123 1124 /*static*/ void XMLNode::DeleteNode( XMLNode* node ) 1125 { 1126 if ( node == 0 ) { 1127 return; 1128 } 1129 TIXMLASSERT(node->_document); 1130 if (!node->ToDocument()) { 1131 node->_document->MarkInUse(node); 1132 } 1133 1134 MemPool* pool = node->_memPool; 1135 node->~XMLNode(); 1136 pool->Free( node ); 1137 } 1138 1139 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const 1140 { 1141 TIXMLASSERT( insertThis ); 1142 TIXMLASSERT( insertThis->_document == _document ); 1143 1144 if (insertThis->_parent) { 1145 insertThis->_parent->Unlink( insertThis ); 1146 } 1147 else { 1148 insertThis->_document->MarkInUse(insertThis); 1149 insertThis->_memPool->SetTracked(); 1150 } 1151 } 1152 1153 const XMLElement* XMLNode::ToElementWithName( const char* name ) const 1154 { 1155 const XMLElement* element = this->ToElement(); 1156 if ( element == 0 ) { 1157 return 0; 1158 } 1159 if ( name == 0 ) { 1160 return element; 1161 } 1162 if ( XMLUtil::StringEqual( element->Name(), name ) ) { 1163 return element; 1164 } 1165 return 0; 1166 } 1167 1168 // --------- XMLText ---------- // 1169 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) 1170 { 1171 if ( this->CData() ) { 1172 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); 1173 if ( !p ) { 1174 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); 1175 } 1176 return p; 1177 } 1178 else { 1179 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; 1180 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { 1181 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; 1182 } 1183 1184 p = _value.ParseText( p, "<", flags, curLineNumPtr ); 1185 if ( p && *p ) { 1186 return p-1; 1187 } 1188 if ( !p ) { 1189 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); 1190 } 1191 } 1192 return 0; 1193 } 1194 1195 1196 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const 1197 { 1198 if ( !doc ) { 1199 doc = _document; 1200 } 1201 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? 1202 text->SetCData( this->CData() ); 1203 return text; 1204 } 1205 1206 1207 bool XMLText::ShallowEqual( const XMLNode* compare ) const 1208 { 1209 TIXMLASSERT( compare ); 1210 const XMLText* text = compare->ToText(); 1211 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); 1212 } 1213 1214 1215 bool XMLText::Accept( XMLVisitor* visitor ) const 1216 { 1217 TIXMLASSERT( visitor ); 1218 return visitor->Visit( *this ); 1219 } 1220 1221 1222 // --------- XMLComment ---------- // 1223 1224 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) 1225 { 1226 } 1227 1228 1229 XMLComment::~XMLComment() 1230 { 1231 } 1232 1233 1234 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) 1235 { 1236 // Comment parses as text. 1237 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); 1238 if ( p == 0 ) { 1239 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); 1240 } 1241 return p; 1242 } 1243 1244 1245 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const 1246 { 1247 if ( !doc ) { 1248 doc = _document; 1249 } 1250 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? 1251 return comment; 1252 } 1253 1254 1255 bool XMLComment::ShallowEqual( const XMLNode* compare ) const 1256 { 1257 TIXMLASSERT( compare ); 1258 const XMLComment* comment = compare->ToComment(); 1259 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); 1260 } 1261 1262 1263 bool XMLComment::Accept( XMLVisitor* visitor ) const 1264 { 1265 TIXMLASSERT( visitor ); 1266 return visitor->Visit( *this ); 1267 } 1268 1269 1270 // --------- XMLDeclaration ---------- // 1271 1272 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) 1273 { 1274 } 1275 1276 1277 XMLDeclaration::~XMLDeclaration() 1278 { 1279 //printf( "~XMLDeclaration\n" ); 1280 } 1281 1282 1283 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) 1284 { 1285 // Declaration parses as text. 1286 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); 1287 if ( p == 0 ) { 1288 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); 1289 } 1290 return p; 1291 } 1292 1293 1294 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const 1295 { 1296 if ( !doc ) { 1297 doc = _document; 1298 } 1299 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? 1300 return dec; 1301 } 1302 1303 1304 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const 1305 { 1306 TIXMLASSERT( compare ); 1307 const XMLDeclaration* declaration = compare->ToDeclaration(); 1308 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); 1309 } 1310 1311 1312 1313 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const 1314 { 1315 TIXMLASSERT( visitor ); 1316 return visitor->Visit( *this ); 1317 } 1318 1319 // --------- XMLUnknown ---------- // 1320 1321 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) 1322 { 1323 } 1324 1325 1326 XMLUnknown::~XMLUnknown() 1327 { 1328 } 1329 1330 1331 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) 1332 { 1333 // Unknown parses as text. 1334 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); 1335 if ( !p ) { 1336 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); 1337 } 1338 return p; 1339 } 1340 1341 1342 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const 1343 { 1344 if ( !doc ) { 1345 doc = _document; 1346 } 1347 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? 1348 return text; 1349 } 1350 1351 1352 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const 1353 { 1354 TIXMLASSERT( compare ); 1355 const XMLUnknown* unknown = compare->ToUnknown(); 1356 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); 1357 } 1358 1359 1360 bool XMLUnknown::Accept( XMLVisitor* visitor ) const 1361 { 1362 TIXMLASSERT( visitor ); 1363 return visitor->Visit( *this ); 1364 } 1365 1366 // --------- XMLAttribute ---------- // 1367 1368 const char* XMLAttribute::Name() const 1369 { 1370 return _name.GetStr(); 1371 } 1372 1373 const char* XMLAttribute::Value() const 1374 { 1375 return _value.GetStr(); 1376 } 1377 1378 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) 1379 { 1380 // Parse using the name rules: bug fix, was using ParseText before 1381 p = _name.ParseName( p ); 1382 if ( !p || !*p ) { 1383 return 0; 1384 } 1385 1386 // Skip white space before = 1387 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); 1388 if ( *p != '=' ) { 1389 return 0; 1390 } 1391 1392 ++p; // move up to opening quote 1393 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); 1394 if ( *p != '\"' && *p != '\'' ) { 1395 return 0; 1396 } 1397 1398 const char endTag[2] = { *p, 0 }; 1399 ++p; // move past opening quote 1400 1401 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); 1402 return p; 1403 } 1404 1405 1406 void XMLAttribute::SetName( const char* n ) 1407 { 1408 _name.SetStr( n ); 1409 } 1410 1411 1412 XMLError XMLAttribute::QueryIntValue( int* value ) const 1413 { 1414 if ( XMLUtil::ToInt( Value(), value )) { 1415 return XML_SUCCESS; 1416 } 1417 return XML_WRONG_ATTRIBUTE_TYPE; 1418 } 1419 1420 1421 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const 1422 { 1423 if ( XMLUtil::ToUnsigned( Value(), value )) { 1424 return XML_SUCCESS; 1425 } 1426 return XML_WRONG_ATTRIBUTE_TYPE; 1427 } 1428 1429 1430 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const 1431 { 1432 if (XMLUtil::ToInt64(Value(), value)) { 1433 return XML_SUCCESS; 1434 } 1435 return XML_WRONG_ATTRIBUTE_TYPE; 1436 } 1437 1438 1439 XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const 1440 { 1441 if(XMLUtil::ToUnsigned64(Value(), value)) { 1442 return XML_SUCCESS; 1443 } 1444 return XML_WRONG_ATTRIBUTE_TYPE; 1445 } 1446 1447 1448 XMLError XMLAttribute::QueryBoolValue( bool* value ) const 1449 { 1450 if ( XMLUtil::ToBool( Value(), value )) { 1451 return XML_SUCCESS; 1452 } 1453 return XML_WRONG_ATTRIBUTE_TYPE; 1454 } 1455 1456 1457 XMLError XMLAttribute::QueryFloatValue( float* value ) const 1458 { 1459 if ( XMLUtil::ToFloat( Value(), value )) { 1460 return XML_SUCCESS; 1461 } 1462 return XML_WRONG_ATTRIBUTE_TYPE; 1463 } 1464 1465 1466 XMLError XMLAttribute::QueryDoubleValue( double* value ) const 1467 { 1468 if ( XMLUtil::ToDouble( Value(), value )) { 1469 return XML_SUCCESS; 1470 } 1471 return XML_WRONG_ATTRIBUTE_TYPE; 1472 } 1473 1474 1475 void XMLAttribute::SetAttribute( const char* v ) 1476 { 1477 _value.SetStr( v ); 1478 } 1479 1480 1481 void XMLAttribute::SetAttribute( int v ) 1482 { 1483 char buf[BUF_SIZE]; 1484 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1485 _value.SetStr( buf ); 1486 } 1487 1488 1489 void XMLAttribute::SetAttribute( unsigned v ) 1490 { 1491 char buf[BUF_SIZE]; 1492 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1493 _value.SetStr( buf ); 1494 } 1495 1496 1497 void XMLAttribute::SetAttribute(int64_t v) 1498 { 1499 char buf[BUF_SIZE]; 1500 XMLUtil::ToStr(v, buf, BUF_SIZE); 1501 _value.SetStr(buf); 1502 } 1503 1504 void XMLAttribute::SetAttribute(uint64_t v) 1505 { 1506 char buf[BUF_SIZE]; 1507 XMLUtil::ToStr(v, buf, BUF_SIZE); 1508 _value.SetStr(buf); 1509 } 1510 1511 1512 void XMLAttribute::SetAttribute( bool v ) 1513 { 1514 char buf[BUF_SIZE]; 1515 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1516 _value.SetStr( buf ); 1517 } 1518 1519 void XMLAttribute::SetAttribute( double v ) 1520 { 1521 char buf[BUF_SIZE]; 1522 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1523 _value.SetStr( buf ); 1524 } 1525 1526 void XMLAttribute::SetAttribute( float v ) 1527 { 1528 char buf[BUF_SIZE]; 1529 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1530 _value.SetStr( buf ); 1531 } 1532 1533 1534 // --------- XMLElement ---------- // 1535 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), 1536 _closingType( OPEN ), 1537 _rootAttribute( 0 ) 1538 { 1539 } 1540 1541 1542 XMLElement::~XMLElement() 1543 { 1544 while( _rootAttribute ) { 1545 XMLAttribute* next = _rootAttribute->_next; 1546 DeleteAttribute( _rootAttribute ); 1547 _rootAttribute = next; 1548 } 1549 } 1550 1551 1552 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const 1553 { 1554 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { 1555 if ( XMLUtil::StringEqual( a->Name(), name ) ) { 1556 return a; 1557 } 1558 } 1559 return 0; 1560 } 1561 1562 1563 const char* XMLElement::Attribute( const char* name, const char* value ) const 1564 { 1565 const XMLAttribute* a = FindAttribute( name ); 1566 if ( !a ) { 1567 return 0; 1568 } 1569 if ( !value || XMLUtil::StringEqual( a->Value(), value )) { 1570 return a->Value(); 1571 } 1572 return 0; 1573 } 1574 1575 int XMLElement::IntAttribute(const char* name, int defaultValue) const 1576 { 1577 int i = defaultValue; 1578 QueryIntAttribute(name, &i); 1579 return i; 1580 } 1581 1582 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const 1583 { 1584 unsigned i = defaultValue; 1585 QueryUnsignedAttribute(name, &i); 1586 return i; 1587 } 1588 1589 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const 1590 { 1591 int64_t i = defaultValue; 1592 QueryInt64Attribute(name, &i); 1593 return i; 1594 } 1595 1596 uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const 1597 { 1598 uint64_t i = defaultValue; 1599 QueryUnsigned64Attribute(name, &i); 1600 return i; 1601 } 1602 1603 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const 1604 { 1605 bool b = defaultValue; 1606 QueryBoolAttribute(name, &b); 1607 return b; 1608 } 1609 1610 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const 1611 { 1612 double d = defaultValue; 1613 QueryDoubleAttribute(name, &d); 1614 return d; 1615 } 1616 1617 float XMLElement::FloatAttribute(const char* name, float defaultValue) const 1618 { 1619 float f = defaultValue; 1620 QueryFloatAttribute(name, &f); 1621 return f; 1622 } 1623 1624 const char* XMLElement::GetText() const 1625 { 1626 if ( FirstChild() && FirstChild()->ToText() ) { 1627 return FirstChild()->Value(); 1628 } 1629 return 0; 1630 } 1631 1632 1633 void XMLElement::SetText( const char* inText ) 1634 { 1635 if ( FirstChild() && FirstChild()->ToText() ) 1636 FirstChild()->SetValue( inText ); 1637 else { 1638 XMLText* theText = GetDocument()->NewText( inText ); 1639 InsertFirstChild( theText ); 1640 } 1641 } 1642 1643 1644 void XMLElement::SetText( int v ) 1645 { 1646 char buf[BUF_SIZE]; 1647 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1648 SetText( buf ); 1649 } 1650 1651 1652 void XMLElement::SetText( unsigned v ) 1653 { 1654 char buf[BUF_SIZE]; 1655 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1656 SetText( buf ); 1657 } 1658 1659 1660 void XMLElement::SetText(int64_t v) 1661 { 1662 char buf[BUF_SIZE]; 1663 XMLUtil::ToStr(v, buf, BUF_SIZE); 1664 SetText(buf); 1665 } 1666 1667 void XMLElement::SetText(uint64_t v) { 1668 char buf[BUF_SIZE]; 1669 XMLUtil::ToStr(v, buf, BUF_SIZE); 1670 SetText(buf); 1671 } 1672 1673 1674 void XMLElement::SetText( bool v ) 1675 { 1676 char buf[BUF_SIZE]; 1677 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1678 SetText( buf ); 1679 } 1680 1681 1682 void XMLElement::SetText( float v ) 1683 { 1684 char buf[BUF_SIZE]; 1685 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1686 SetText( buf ); 1687 } 1688 1689 1690 void XMLElement::SetText( double v ) 1691 { 1692 char buf[BUF_SIZE]; 1693 XMLUtil::ToStr( v, buf, BUF_SIZE ); 1694 SetText( buf ); 1695 } 1696 1697 1698 XMLError XMLElement::QueryIntText( int* ival ) const 1699 { 1700 if ( FirstChild() && FirstChild()->ToText() ) { 1701 const char* t = FirstChild()->Value(); 1702 if ( XMLUtil::ToInt( t, ival ) ) { 1703 return XML_SUCCESS; 1704 } 1705 return XML_CAN_NOT_CONVERT_TEXT; 1706 } 1707 return XML_NO_TEXT_NODE; 1708 } 1709 1710 1711 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const 1712 { 1713 if ( FirstChild() && FirstChild()->ToText() ) { 1714 const char* t = FirstChild()->Value(); 1715 if ( XMLUtil::ToUnsigned( t, uval ) ) { 1716 return XML_SUCCESS; 1717 } 1718 return XML_CAN_NOT_CONVERT_TEXT; 1719 } 1720 return XML_NO_TEXT_NODE; 1721 } 1722 1723 1724 XMLError XMLElement::QueryInt64Text(int64_t* ival) const 1725 { 1726 if (FirstChild() && FirstChild()->ToText()) { 1727 const char* t = FirstChild()->Value(); 1728 if (XMLUtil::ToInt64(t, ival)) { 1729 return XML_SUCCESS; 1730 } 1731 return XML_CAN_NOT_CONVERT_TEXT; 1732 } 1733 return XML_NO_TEXT_NODE; 1734 } 1735 1736 1737 XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const 1738 { 1739 if(FirstChild() && FirstChild()->ToText()) { 1740 const char* t = FirstChild()->Value(); 1741 if(XMLUtil::ToUnsigned64(t, ival)) { 1742 return XML_SUCCESS; 1743 } 1744 return XML_CAN_NOT_CONVERT_TEXT; 1745 } 1746 return XML_NO_TEXT_NODE; 1747 } 1748 1749 1750 XMLError XMLElement::QueryBoolText( bool* bval ) const 1751 { 1752 if ( FirstChild() && FirstChild()->ToText() ) { 1753 const char* t = FirstChild()->Value(); 1754 if ( XMLUtil::ToBool( t, bval ) ) { 1755 return XML_SUCCESS; 1756 } 1757 return XML_CAN_NOT_CONVERT_TEXT; 1758 } 1759 return XML_NO_TEXT_NODE; 1760 } 1761 1762 1763 XMLError XMLElement::QueryDoubleText( double* dval ) const 1764 { 1765 if ( FirstChild() && FirstChild()->ToText() ) { 1766 const char* t = FirstChild()->Value(); 1767 if ( XMLUtil::ToDouble( t, dval ) ) { 1768 return XML_SUCCESS; 1769 } 1770 return XML_CAN_NOT_CONVERT_TEXT; 1771 } 1772 return XML_NO_TEXT_NODE; 1773 } 1774 1775 1776 XMLError XMLElement::QueryFloatText( float* fval ) const 1777 { 1778 if ( FirstChild() && FirstChild()->ToText() ) { 1779 const char* t = FirstChild()->Value(); 1780 if ( XMLUtil::ToFloat( t, fval ) ) { 1781 return XML_SUCCESS; 1782 } 1783 return XML_CAN_NOT_CONVERT_TEXT; 1784 } 1785 return XML_NO_TEXT_NODE; 1786 } 1787 1788 int XMLElement::IntText(int defaultValue) const 1789 { 1790 int i = defaultValue; 1791 QueryIntText(&i); 1792 return i; 1793 } 1794 1795 unsigned XMLElement::UnsignedText(unsigned defaultValue) const 1796 { 1797 unsigned i = defaultValue; 1798 QueryUnsignedText(&i); 1799 return i; 1800 } 1801 1802 int64_t XMLElement::Int64Text(int64_t defaultValue) const 1803 { 1804 int64_t i = defaultValue; 1805 QueryInt64Text(&i); 1806 return i; 1807 } 1808 1809 uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const 1810 { 1811 uint64_t i = defaultValue; 1812 QueryUnsigned64Text(&i); 1813 return i; 1814 } 1815 1816 bool XMLElement::BoolText(bool defaultValue) const 1817 { 1818 bool b = defaultValue; 1819 QueryBoolText(&b); 1820 return b; 1821 } 1822 1823 double XMLElement::DoubleText(double defaultValue) const 1824 { 1825 double d = defaultValue; 1826 QueryDoubleText(&d); 1827 return d; 1828 } 1829 1830 float XMLElement::FloatText(float defaultValue) const 1831 { 1832 float f = defaultValue; 1833 QueryFloatText(&f); 1834 return f; 1835 } 1836 1837 1838 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) 1839 { 1840 XMLAttribute* last = 0; 1841 XMLAttribute* attrib = 0; 1842 for( attrib = _rootAttribute; 1843 attrib; 1844 last = attrib, attrib = attrib->_next ) { 1845 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { 1846 break; 1847 } 1848 } 1849 if ( !attrib ) { 1850 attrib = CreateAttribute(); 1851 TIXMLASSERT( attrib ); 1852 if ( last ) { 1853 TIXMLASSERT( last->_next == 0 ); 1854 last->_next = attrib; 1855 } 1856 else { 1857 TIXMLASSERT( _rootAttribute == 0 ); 1858 _rootAttribute = attrib; 1859 } 1860 attrib->SetName( name ); 1861 } 1862 return attrib; 1863 } 1864 1865 1866 void XMLElement::DeleteAttribute( const char* name ) 1867 { 1868 XMLAttribute* prev = 0; 1869 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { 1870 if ( XMLUtil::StringEqual( name, a->Name() ) ) { 1871 if ( prev ) { 1872 prev->_next = a->_next; 1873 } 1874 else { 1875 _rootAttribute = a->_next; 1876 } 1877 DeleteAttribute( a ); 1878 break; 1879 } 1880 prev = a; 1881 } 1882 } 1883 1884 1885 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) 1886 { 1887 XMLAttribute* prevAttribute = 0; 1888 1889 // Read the attributes. 1890 while( p ) { 1891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); 1892 if ( !(*p) ) { 1893 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); 1894 return 0; 1895 } 1896 1897 // attribute. 1898 if (XMLUtil::IsNameStartChar( *p ) ) { 1899 XMLAttribute* attrib = CreateAttribute(); 1900 TIXMLASSERT( attrib ); 1901 attrib->_parseLineNum = _document->_parseCurLineNum; 1902 1903 const int attrLineNum = attrib->_parseLineNum; 1904 1905 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); 1906 if ( !p || Attribute( attrib->Name() ) ) { 1907 DeleteAttribute( attrib ); 1908 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); 1909 return 0; 1910 } 1911 // There is a minor bug here: if the attribute in the source xml 1912 // document is duplicated, it will not be detected and the 1913 // attribute will be doubly added. However, tracking the 'prevAttribute' 1914 // avoids re-scanning the attribute list. Preferring performance for 1915 // now, may reconsider in the future. 1916 if ( prevAttribute ) { 1917 TIXMLASSERT( prevAttribute->_next == 0 ); 1918 prevAttribute->_next = attrib; 1919 } 1920 else { 1921 TIXMLASSERT( _rootAttribute == 0 ); 1922 _rootAttribute = attrib; 1923 } 1924 prevAttribute = attrib; 1925 } 1926 // end of the tag 1927 else if ( *p == '>' ) { 1928 ++p; 1929 break; 1930 } 1931 // end of the tag 1932 else if ( *p == '/' && *(p+1) == '>' ) { 1933 _closingType = CLOSED; 1934 return p+2; // done; sealed element. 1935 } 1936 else { 1937 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); 1938 return 0; 1939 } 1940 } 1941 return p; 1942 } 1943 1944 void XMLElement::DeleteAttribute( XMLAttribute* attribute ) 1945 { 1946 if ( attribute == 0 ) { 1947 return; 1948 } 1949 MemPool* pool = attribute->_memPool; 1950 attribute->~XMLAttribute(); 1951 pool->Free( attribute ); 1952 } 1953 1954 XMLAttribute* XMLElement::CreateAttribute() 1955 { 1956 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); 1957 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); 1958 TIXMLASSERT( attrib ); 1959 attrib->_memPool = &_document->_attributePool; 1960 attrib->_memPool->SetTracked(); 1961 return attrib; 1962 } 1963 1964 1965 XMLElement* XMLElement::InsertNewChildElement(const char* name) 1966 { 1967 XMLElement* node = _document->NewElement(name); 1968 return InsertEndChild(node) ? node : 0; 1969 } 1970 1971 XMLComment* XMLElement::InsertNewComment(const char* comment) 1972 { 1973 XMLComment* node = _document->NewComment(comment); 1974 return InsertEndChild(node) ? node : 0; 1975 } 1976 1977 XMLText* XMLElement::InsertNewText(const char* text) 1978 { 1979 XMLText* node = _document->NewText(text); 1980 return InsertEndChild(node) ? node : 0; 1981 } 1982 1983 XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) 1984 { 1985 XMLDeclaration* node = _document->NewDeclaration(text); 1986 return InsertEndChild(node) ? node : 0; 1987 } 1988 1989 XMLUnknown* XMLElement::InsertNewUnknown(const char* text) 1990 { 1991 XMLUnknown* node = _document->NewUnknown(text); 1992 return InsertEndChild(node) ? node : 0; 1993 } 1994 1995 1996 1997 // 1998 // <ele></ele> 1999 // <ele>foo<b>bar</b></ele> 2000 // 2001 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) 2002 { 2003 // Read the element name. 2004 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); 2005 2006 // The closing element is the </element> form. It is 2007 // parsed just like a regular element then deleted from 2008 // the DOM. 2009 if ( *p == '/' ) { 2010 _closingType = CLOSING; 2011 ++p; 2012 } 2013 2014 p = _value.ParseName( p ); 2015 if ( _value.Empty() ) { 2016 return 0; 2017 } 2018 2019 p = ParseAttributes( p, curLineNumPtr ); 2020 if ( !p || !*p || _closingType != OPEN ) { 2021 return p; 2022 } 2023 2024 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); 2025 return p; 2026 } 2027 2028 2029 2030 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const 2031 { 2032 if ( !doc ) { 2033 doc = _document; 2034 } 2035 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? 2036 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { 2037 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? 2038 } 2039 return element; 2040 } 2041 2042 2043 bool XMLElement::ShallowEqual( const XMLNode* compare ) const 2044 { 2045 TIXMLASSERT( compare ); 2046 const XMLElement* other = compare->ToElement(); 2047 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { 2048 2049 const XMLAttribute* a=FirstAttribute(); 2050 const XMLAttribute* b=other->FirstAttribute(); 2051 2052 while ( a && b ) { 2053 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { 2054 return false; 2055 } 2056 a = a->Next(); 2057 b = b->Next(); 2058 } 2059 if ( a || b ) { 2060 // different count 2061 return false; 2062 } 2063 return true; 2064 } 2065 return false; 2066 } 2067 2068 2069 bool XMLElement::Accept( XMLVisitor* visitor ) const 2070 { 2071 TIXMLASSERT( visitor ); 2072 if ( visitor->VisitEnter( *this, _rootAttribute ) ) { 2073 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { 2074 if ( !node->Accept( visitor ) ) { 2075 break; 2076 } 2077 } 2078 } 2079 return visitor->VisitExit( *this ); 2080 } 2081 2082 2083 // --------- XMLDocument ----------- // 2084 2085 // Warning: List must match 'enum XMLError' 2086 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { 2087 "XML_SUCCESS", 2088 "XML_NO_ATTRIBUTE", 2089 "XML_WRONG_ATTRIBUTE_TYPE", 2090 "XML_ERROR_FILE_NOT_FOUND", 2091 "XML_ERROR_FILE_COULD_NOT_BE_OPENED", 2092 "XML_ERROR_FILE_READ_ERROR", 2093 "XML_ERROR_PARSING_ELEMENT", 2094 "XML_ERROR_PARSING_ATTRIBUTE", 2095 "XML_ERROR_PARSING_TEXT", 2096 "XML_ERROR_PARSING_CDATA", 2097 "XML_ERROR_PARSING_COMMENT", 2098 "XML_ERROR_PARSING_DECLARATION", 2099 "XML_ERROR_PARSING_UNKNOWN", 2100 "XML_ERROR_EMPTY_DOCUMENT", 2101 "XML_ERROR_MISMATCHED_ELEMENT", 2102 "XML_ERROR_PARSING", 2103 "XML_CAN_NOT_CONVERT_TEXT", 2104 "XML_NO_TEXT_NODE", 2105 "XML_ELEMENT_DEPTH_EXCEEDED" 2106 }; 2107 2108 2109 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : 2110 XMLNode( 0 ), 2111 _writeBOM( false ), 2112 _processEntities( processEntities ), 2113 _errorID(XML_SUCCESS), 2114 _whitespaceMode( whitespaceMode ), 2115 _errorStr(), 2116 _errorLineNum( 0 ), 2117 _charBuffer( 0 ), 2118 _parseCurLineNum( 0 ), 2119 _parsingDepth(0), 2120 _unlinked(), 2121 _elementPool(), 2122 _attributePool(), 2123 _textPool(), 2124 _commentPool() 2125 { 2126 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) 2127 _document = this; 2128 } 2129 2130 2131 XMLDocument::~XMLDocument() 2132 { 2133 Clear(); 2134 } 2135 2136 2137 void XMLDocument::MarkInUse(const XMLNode* const node) 2138 { 2139 TIXMLASSERT(node); 2140 TIXMLASSERT(node->_parent == 0); 2141 2142 for (int i = 0; i < _unlinked.Size(); ++i) { 2143 if (node == _unlinked[i]) { 2144 _unlinked.SwapRemove(i); 2145 break; 2146 } 2147 } 2148 } 2149 2150 void XMLDocument::Clear() 2151 { 2152 DeleteChildren(); 2153 while( _unlinked.Size()) { 2154 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. 2155 } 2156 2157 #ifdef TINYXML2_DEBUG 2158 const bool hadError = Error(); 2159 #endif 2160 ClearError(); 2161 2162 delete [] _charBuffer; 2163 _charBuffer = 0; 2164 _parsingDepth = 0; 2165 2166 #if 0 2167 _textPool.Trace( "text" ); 2168 _elementPool.Trace( "element" ); 2169 _commentPool.Trace( "comment" ); 2170 _attributePool.Trace( "attribute" ); 2171 #endif 2172 2173 #ifdef TINYXML2_DEBUG 2174 if ( !hadError ) { 2175 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); 2176 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); 2177 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); 2178 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); 2179 } 2180 #endif 2181 } 2182 2183 2184 void XMLDocument::DeepCopy(XMLDocument* target) const 2185 { 2186 TIXMLASSERT(target); 2187 if (target == this) { 2188 return; // technically success - a no-op. 2189 } 2190 2191 target->Clear(); 2192 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { 2193 target->InsertEndChild(node->DeepClone(target)); 2194 } 2195 } 2196 2197 XMLElement* XMLDocument::NewElement( const char* name ) 2198 { 2199 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool ); 2200 ele->SetName( name ); 2201 return ele; 2202 } 2203 2204 2205 XMLComment* XMLDocument::NewComment( const char* str ) 2206 { 2207 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool ); 2208 comment->SetValue( str ); 2209 return comment; 2210 } 2211 2212 2213 XMLText* XMLDocument::NewText( const char* str ) 2214 { 2215 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool ); 2216 text->SetValue( str ); 2217 return text; 2218 } 2219 2220 2221 XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) 2222 { 2223 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool ); 2224 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); 2225 return dec; 2226 } 2227 2228 2229 XMLUnknown* XMLDocument::NewUnknown( const char* str ) 2230 { 2231 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool ); 2232 unk->SetValue( str ); 2233 return unk; 2234 } 2235 2236 static FILE* callfopen( const char* filepath, const char* mode ) 2237 { 2238 TIXMLASSERT( filepath ); 2239 TIXMLASSERT( mode ); 2240 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) 2241 FILE* fp = 0; 2242 const errno_t err = fopen_s( &fp, filepath, mode ); 2243 if ( err ) { 2244 return 0; 2245 } 2246 #else 2247 FILE* fp = fopen( filepath, mode ); 2248 #endif 2249 return fp; 2250 } 2251 2252 void XMLDocument::DeleteNode( XMLNode* node ) { 2253 TIXMLASSERT( node ); 2254 TIXMLASSERT(node->_document == this ); 2255 if (node->_parent) { 2256 node->_parent->DeleteChild( node ); 2257 } 2258 else { 2259 // Isn't in the tree. 2260 // Use the parent delete. 2261 // Also, we need to mark it tracked: we 'know' 2262 // it was never used. 2263 node->_memPool->SetTracked(); 2264 // Call the static XMLNode version: 2265 XMLNode::DeleteNode(node); 2266 } 2267 } 2268 2269 2270 XMLError XMLDocument::LoadFile( const char* filename ) 2271 { 2272 if ( !filename ) { 2273 TIXMLASSERT( false ); 2274 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" ); 2275 return _errorID; 2276 } 2277 2278 Clear(); 2279 FILE* fp = callfopen( filename, "rb" ); 2280 if ( !fp ) { 2281 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); 2282 return _errorID; 2283 } 2284 LoadFile( fp ); 2285 fclose( fp ); 2286 return _errorID; 2287 } 2288 2289 // This is likely overengineered template art to have a check that unsigned long value incremented 2290 // by one still fits into size_t. If size_t type is larger than unsigned long type 2291 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit 2292 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check 2293 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long 2294 // types sizes relate to each other. 2295 template 2296 <bool = (sizeof(unsigned long) >= sizeof(size_t))> 2297 struct LongFitsIntoSizeTMinusOne { 2298 static bool Fits( unsigned long value ) 2299 { 2300 return value < static_cast<size_t>(-1); 2301 } 2302 }; 2303 2304 template <> 2305 struct LongFitsIntoSizeTMinusOne<false> { 2306 static bool Fits( unsigned long ) 2307 { 2308 return true; 2309 } 2310 }; 2311 2312 XMLError XMLDocument::LoadFile( FILE* fp ) 2313 { 2314 Clear(); 2315 2316 fseek( fp, 0, SEEK_SET ); 2317 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { 2318 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); 2319 return _errorID; 2320 } 2321 2322 fseek( fp, 0, SEEK_END ); 2323 const long filelength = ftell( fp ); 2324 fseek( fp, 0, SEEK_SET ); 2325 if ( filelength == -1L ) { 2326 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); 2327 return _errorID; 2328 } 2329 TIXMLASSERT( filelength >= 0 ); 2330 2331 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { 2332 // Cannot handle files which won't fit in buffer together with null terminator 2333 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); 2334 return _errorID; 2335 } 2336 2337 if ( filelength == 0 ) { 2338 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 2339 return _errorID; 2340 } 2341 2342 const size_t size = filelength; 2343 TIXMLASSERT( _charBuffer == 0 ); 2344 _charBuffer = new char[size+1]; 2345 const size_t read = fread( _charBuffer, 1, size, fp ); 2346 if ( read != size ) { 2347 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); 2348 return _errorID; 2349 } 2350 2351 _charBuffer[size] = 0; 2352 2353 Parse(); 2354 return _errorID; 2355 } 2356 2357 2358 XMLError XMLDocument::SaveFile( const char* filename, bool compact ) 2359 { 2360 if ( !filename ) { 2361 TIXMLASSERT( false ); 2362 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" ); 2363 return _errorID; 2364 } 2365 2366 FILE* fp = callfopen( filename, "w" ); 2367 if ( !fp ) { 2368 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); 2369 return _errorID; 2370 } 2371 SaveFile(fp, compact); 2372 fclose( fp ); 2373 return _errorID; 2374 } 2375 2376 2377 XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) 2378 { 2379 // Clear any error from the last save, otherwise it will get reported 2380 // for *this* call. 2381 ClearError(); 2382 XMLPrinter stream( fp, compact ); 2383 Print( &stream ); 2384 return _errorID; 2385 } 2386 2387 2388 XMLError XMLDocument::Parse( const char* p, size_t len ) 2389 { 2390 Clear(); 2391 2392 if ( len == 0 || !p || !*p ) { 2393 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 2394 return _errorID; 2395 } 2396 if ( len == static_cast<size_t>(-1) ) { 2397 len = strlen( p ); 2398 } 2399 TIXMLASSERT( _charBuffer == 0 ); 2400 _charBuffer = new char[ len+1 ]; 2401 memcpy( _charBuffer, p, len ); 2402 _charBuffer[len] = 0; 2403 2404 Parse(); 2405 if ( Error() ) { 2406 // clean up now essentially dangling memory. 2407 // and the parse fail can put objects in the 2408 // pools that are dead and inaccessible. 2409 DeleteChildren(); 2410 _elementPool.Clear(); 2411 _attributePool.Clear(); 2412 _textPool.Clear(); 2413 _commentPool.Clear(); 2414 } 2415 return _errorID; 2416 } 2417 2418 2419 void XMLDocument::Print( XMLPrinter* streamer ) const 2420 { 2421 if ( streamer ) { 2422 Accept( streamer ); 2423 } 2424 else { 2425 XMLPrinter stdoutStreamer( stdout ); 2426 Accept( &stdoutStreamer ); 2427 } 2428 } 2429 2430 2431 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) 2432 { 2433 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); 2434 _errorID = error; 2435 _errorLineNum = lineNum; 2436 _errorStr.Reset(); 2437 2438 const size_t BUFFER_SIZE = 1000; 2439 char* buffer = new char[BUFFER_SIZE]; 2440 2441 TIXMLASSERT(sizeof(error) <= sizeof(int)); 2442 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); 2443 2444 if (format) { 2445 size_t len = strlen(buffer); 2446 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); 2447 len = strlen(buffer); 2448 2449 va_list va; 2450 va_start(va, format); 2451 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); 2452 va_end(va); 2453 } 2454 _errorStr.SetStr(buffer); 2455 delete[] buffer; 2456 } 2457 2458 2459 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) 2460 { 2461 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); 2462 const char* errorName = _errorNames[errorID]; 2463 TIXMLASSERT( errorName && errorName[0] ); 2464 return errorName; 2465 } 2466 2467 const char* XMLDocument::ErrorStr() const 2468 { 2469 return _errorStr.Empty() ? "" : _errorStr.GetStr(); 2470 } 2471 2472 2473 void XMLDocument::PrintError() const 2474 { 2475 printf("%s\n", ErrorStr()); 2476 } 2477 2478 const char* XMLDocument::ErrorName() const 2479 { 2480 return ErrorIDToName(_errorID); 2481 } 2482 2483 void XMLDocument::Parse() 2484 { 2485 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously 2486 TIXMLASSERT( _charBuffer ); 2487 _parseCurLineNum = 1; 2488 _parseLineNum = 1; 2489 char* p = _charBuffer; 2490 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); 2491 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) ); 2492 if ( !*p ) { 2493 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 2494 return; 2495 } 2496 ParseDeep(p, 0, &_parseCurLineNum ); 2497 } 2498 2499 void XMLDocument::PushDepth() 2500 { 2501 _parsingDepth++; 2502 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { 2503 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); 2504 } 2505 } 2506 2507 void XMLDocument::PopDepth() 2508 { 2509 TIXMLASSERT(_parsingDepth > 0); 2510 --_parsingDepth; 2511 } 2512 2513 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : 2514 _elementJustOpened( false ), 2515 _stack(), 2516 _firstElement( true ), 2517 _fp( file ), 2518 _depth( depth ), 2519 _textDepth( -1 ), 2520 _processEntities( true ), 2521 _compactMode( compact ), 2522 _buffer() 2523 { 2524 for( int i=0; i<ENTITY_RANGE; ++i ) { 2525 _entityFlag[i] = false; 2526 _restrictedEntityFlag[i] = false; 2527 } 2528 for( int i=0; i<NUM_ENTITIES; ++i ) { 2529 const char entityValue = entities[i].value; 2530 const unsigned char flagIndex = static_cast<unsigned char>(entityValue); 2531 TIXMLASSERT( flagIndex < ENTITY_RANGE ); 2532 _entityFlag[flagIndex] = true; 2533 } 2534 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true; 2535 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true; 2536 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice 2537 _buffer.Push( 0 ); 2538 } 2539 2540 2541 void XMLPrinter::Print( const char* format, ... ) 2542 { 2543 va_list va; 2544 va_start( va, format ); 2545 2546 if ( _fp ) { 2547 vfprintf( _fp, format, va ); 2548 } 2549 else { 2550 const int len = TIXML_VSCPRINTF( format, va ); 2551 // Close out and re-start the va-args 2552 va_end( va ); 2553 TIXMLASSERT( len >= 0 ); 2554 va_start( va, format ); 2555 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); 2556 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. 2557 TIXML_VSNPRINTF( p, len+1, format, va ); 2558 } 2559 va_end( va ); 2560 } 2561 2562 2563 void XMLPrinter::Write( const char* data, size_t size ) 2564 { 2565 if ( _fp ) { 2566 fwrite ( data , sizeof(char), size, _fp); 2567 } 2568 else { 2569 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator. 2570 memcpy( p, data, size ); 2571 p[size] = 0; 2572 } 2573 } 2574 2575 2576 void XMLPrinter::Putc( char ch ) 2577 { 2578 if ( _fp ) { 2579 fputc ( ch, _fp); 2580 } 2581 else { 2582 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. 2583 p[0] = ch; 2584 p[1] = 0; 2585 } 2586 } 2587 2588 2589 void XMLPrinter::PrintSpace( int depth ) 2590 { 2591 for( int i=0; i<depth; ++i ) { 2592 Write( " " ); 2593 } 2594 } 2595 2596 2597 void XMLPrinter::PrintString( const char* p, bool restricted ) 2598 { 2599 // Look for runs of bytes between entities to print. 2600 const char* q = p; 2601 2602 if ( _processEntities ) { 2603 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; 2604 while ( *q ) { 2605 TIXMLASSERT( p <= q ); 2606 // Remember, char is sometimes signed. (How many times has that bitten me?) 2607 if ( *q > 0 && *q < ENTITY_RANGE ) { 2608 // Check for entities. If one is found, flush 2609 // the stream up until the entity, write the 2610 // entity, and keep looking. 2611 if ( flag[static_cast<unsigned char>(*q)] ) { 2612 while ( p < q ) { 2613 const size_t delta = q - p; 2614 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta); 2615 Write( p, toPrint ); 2616 p += toPrint; 2617 } 2618 bool entityPatternPrinted = false; 2619 for( int i=0; i<NUM_ENTITIES; ++i ) { 2620 if ( entities[i].value == *q ) { 2621 Putc( '&' ); 2622 Write( entities[i].pattern, entities[i].length ); 2623 Putc( ';' ); 2624 entityPatternPrinted = true; 2625 break; 2626 } 2627 } 2628 if ( !entityPatternPrinted ) { 2629 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release 2630 TIXMLASSERT( false ); 2631 } 2632 ++p; 2633 } 2634 } 2635 ++q; 2636 TIXMLASSERT( p <= q ); 2637 } 2638 // Flush the remaining string. This will be the entire 2639 // string if an entity wasn't found. 2640 if ( p < q ) { 2641 const size_t delta = q - p; 2642 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta); 2643 Write( p, toPrint ); 2644 } 2645 } 2646 else { 2647 Write( p ); 2648 } 2649 } 2650 2651 2652 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) 2653 { 2654 if ( writeBOM ) { 2655 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; 2656 Write( reinterpret_cast< const char* >( bom ) ); 2657 } 2658 if ( writeDec ) { 2659 PushDeclaration( "xml version=\"1.0\"" ); 2660 } 2661 } 2662 2663 2664 void XMLPrinter::OpenElement( const char* name, bool compactMode ) 2665 { 2666 SealElementIfJustOpened(); 2667 _stack.Push( name ); 2668 2669 if ( _textDepth < 0 && !_firstElement && !compactMode ) { 2670 Putc( '\n' ); 2671 PrintSpace( _depth ); 2672 } 2673 2674 Write ( "<" ); 2675 Write ( name ); 2676 2677 _elementJustOpened = true; 2678 _firstElement = false; 2679 ++_depth; 2680 } 2681 2682 2683 void XMLPrinter::PushAttribute( const char* name, const char* value ) 2684 { 2685 TIXMLASSERT( _elementJustOpened ); 2686 Putc ( ' ' ); 2687 Write( name ); 2688 Write( "=\"" ); 2689 PrintString( value, false ); 2690 Putc ( '\"' ); 2691 } 2692 2693 2694 void XMLPrinter::PushAttribute( const char* name, int v ) 2695 { 2696 char buf[BUF_SIZE]; 2697 XMLUtil::ToStr( v, buf, BUF_SIZE ); 2698 PushAttribute( name, buf ); 2699 } 2700 2701 2702 void XMLPrinter::PushAttribute( const char* name, unsigned v ) 2703 { 2704 char buf[BUF_SIZE]; 2705 XMLUtil::ToStr( v, buf, BUF_SIZE ); 2706 PushAttribute( name, buf ); 2707 } 2708 2709 2710 void XMLPrinter::PushAttribute(const char* name, int64_t v) 2711 { 2712 char buf[BUF_SIZE]; 2713 XMLUtil::ToStr(v, buf, BUF_SIZE); 2714 PushAttribute(name, buf); 2715 } 2716 2717 2718 void XMLPrinter::PushAttribute(const char* name, uint64_t v) 2719 { 2720 char buf[BUF_SIZE]; 2721 XMLUtil::ToStr(v, buf, BUF_SIZE); 2722 PushAttribute(name, buf); 2723 } 2724 2725 2726 void XMLPrinter::PushAttribute( const char* name, bool v ) 2727 { 2728 char buf[BUF_SIZE]; 2729 XMLUtil::ToStr( v, buf, BUF_SIZE ); 2730 PushAttribute( name, buf ); 2731 } 2732 2733 2734 void XMLPrinter::PushAttribute( const char* name, double v ) 2735 { 2736 char buf[BUF_SIZE]; 2737 XMLUtil::ToStr( v, buf, BUF_SIZE ); 2738 PushAttribute( name, buf ); 2739 } 2740 2741 2742 void XMLPrinter::CloseElement( bool compactMode ) 2743 { 2744 --_depth; 2745 const char* name = _stack.Pop(); 2746 2747 if ( _elementJustOpened ) { 2748 Write( "/>" ); 2749 } 2750 else { 2751 if ( _textDepth < 0 && !compactMode) { 2752 Putc( '\n' ); 2753 PrintSpace( _depth ); 2754 } 2755 Write ( "</" ); 2756 Write ( name ); 2757 Write ( ">" ); 2758 } 2759 2760 if ( _textDepth == _depth ) { 2761 _textDepth = -1; 2762 } 2763 if ( _depth == 0 && !compactMode) { 2764 Putc( '\n' ); 2765 } 2766 _elementJustOpened = false; 2767 } 2768 2769 2770 void XMLPrinter::SealElementIfJustOpened() 2771 { 2772 if ( !_elementJustOpened ) { 2773 return; 2774 } 2775 _elementJustOpened = false; 2776 Putc( '>' ); 2777 } 2778 2779 2780 void XMLPrinter::PushText( const char* text, bool cdata ) 2781 { 2782 _textDepth = _depth-1; 2783 2784 SealElementIfJustOpened(); 2785 if ( cdata ) { 2786 Write( "<![CDATA[" ); 2787 Write( text ); 2788 Write( "]]>" ); 2789 } 2790 else { 2791 PrintString( text, true ); 2792 } 2793 } 2794 2795 2796 void XMLPrinter::PushText( int64_t value ) 2797 { 2798 char buf[BUF_SIZE]; 2799 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2800 PushText( buf, false ); 2801 } 2802 2803 2804 void XMLPrinter::PushText( uint64_t value ) 2805 { 2806 char buf[BUF_SIZE]; 2807 XMLUtil::ToStr(value, buf, BUF_SIZE); 2808 PushText(buf, false); 2809 } 2810 2811 2812 void XMLPrinter::PushText( int value ) 2813 { 2814 char buf[BUF_SIZE]; 2815 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2816 PushText( buf, false ); 2817 } 2818 2819 2820 void XMLPrinter::PushText( unsigned value ) 2821 { 2822 char buf[BUF_SIZE]; 2823 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2824 PushText( buf, false ); 2825 } 2826 2827 2828 void XMLPrinter::PushText( bool value ) 2829 { 2830 char buf[BUF_SIZE]; 2831 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2832 PushText( buf, false ); 2833 } 2834 2835 2836 void XMLPrinter::PushText( float value ) 2837 { 2838 char buf[BUF_SIZE]; 2839 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2840 PushText( buf, false ); 2841 } 2842 2843 2844 void XMLPrinter::PushText( double value ) 2845 { 2846 char buf[BUF_SIZE]; 2847 XMLUtil::ToStr( value, buf, BUF_SIZE ); 2848 PushText( buf, false ); 2849 } 2850 2851 2852 void XMLPrinter::PushComment( const char* comment ) 2853 { 2854 SealElementIfJustOpened(); 2855 if ( _textDepth < 0 && !_firstElement && !_compactMode) { 2856 Putc( '\n' ); 2857 PrintSpace( _depth ); 2858 } 2859 _firstElement = false; 2860 2861 Write( "<!--" ); 2862 Write( comment ); 2863 Write( "-->" ); 2864 } 2865 2866 2867 void XMLPrinter::PushDeclaration( const char* value ) 2868 { 2869 SealElementIfJustOpened(); 2870 if ( _textDepth < 0 && !_firstElement && !_compactMode) { 2871 Putc( '\n' ); 2872 PrintSpace( _depth ); 2873 } 2874 _firstElement = false; 2875 2876 Write( "<?" ); 2877 Write( value ); 2878 Write( "?>" ); 2879 } 2880 2881 2882 void XMLPrinter::PushUnknown( const char* value ) 2883 { 2884 SealElementIfJustOpened(); 2885 if ( _textDepth < 0 && !_firstElement && !_compactMode) { 2886 Putc( '\n' ); 2887 PrintSpace( _depth ); 2888 } 2889 _firstElement = false; 2890 2891 Write( "<!" ); 2892 Write( value ); 2893 Putc( '>' ); 2894 } 2895 2896 2897 bool XMLPrinter::VisitEnter( const XMLDocument& doc ) 2898 { 2899 _processEntities = doc.ProcessEntities(); 2900 if ( doc.HasBOM() ) { 2901 PushHeader( true, false ); 2902 } 2903 return true; 2904 } 2905 2906 2907 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) 2908 { 2909 const XMLElement* parentElem = 0; 2910 if ( element.Parent() ) { 2911 parentElem = element.Parent()->ToElement(); 2912 } 2913 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; 2914 OpenElement( element.Name(), compactMode ); 2915 while ( attribute ) { 2916 PushAttribute( attribute->Name(), attribute->Value() ); 2917 attribute = attribute->Next(); 2918 } 2919 return true; 2920 } 2921 2922 2923 bool XMLPrinter::VisitExit( const XMLElement& element ) 2924 { 2925 CloseElement( CompactMode(element) ); 2926 return true; 2927 } 2928 2929 2930 bool XMLPrinter::Visit( const XMLText& text ) 2931 { 2932 PushText( text.Value(), text.CData() ); 2933 return true; 2934 } 2935 2936 2937 bool XMLPrinter::Visit( const XMLComment& comment ) 2938 { 2939 PushComment( comment.Value() ); 2940 return true; 2941 } 2942 2943 bool XMLPrinter::Visit( const XMLDeclaration& declaration ) 2944 { 2945 PushDeclaration( declaration.Value() ); 2946 return true; 2947 } 2948 2949 2950 bool XMLPrinter::Visit( const XMLUnknown& unknown ) 2951 { 2952 PushUnknown( unknown.Value() ); 2953 return true; 2954 } 2955 2956 } // namespace tinyxml2