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 #ifndef TINYXML2_INCLUDED 25 #define TINYXML2_INCLUDED 26 27 #include <cctype> 28 #include <climits> 29 #include <cstdio> 30 #include <cstring> 31 //#include <cstdarg> 32 #include <stdarg.h> 33 /* 34 TODO: intern strings instead of allocation. 35 */ 36 /* 37 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe 38 */ 39 40 #if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) 41 #ifndef DEBUG 42 #define DEBUG 43 #endif 44 #endif 45 46 47 #if defined(DEBUG) 48 #if defined(_MSC_VER) 49 #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() 50 #elif defined (ANDROID_NDK) 51 #include <android/log.h> 52 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } 53 #else 54 #include <assert.h> 55 #define TIXMLASSERT assert 56 #endif 57 #else 58 #define TIXMLASSERT( x ) {} 59 #endif 60 61 62 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) 63 // Microsoft visual studio, version 2005 and higher. 64 /*int _snprintf_s( 65 char *buffer, 66 size_t sizeOfBuffer, 67 size_t count, 68 const char *format [, 69 argument] ... 70 );*/ 71 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) { 72 va_list va; 73 va_start( va, format ); 74 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); 75 va_end( va ); 76 return result; 77 } 78 #define TIXML_SSCANF sscanf_s 79 #else 80 // GCC version 3 and higher 81 //#warning( "Using sn* functions." ) 82 #define TIXML_SNPRINTF snprintf 83 #define TIXML_SSCANF sscanf 84 #endif 85 86 static const int TIXML2_MAJOR_VERSION = 1; 87 static const int TIXML2_MINOR_VERSION = 0; 88 static const int TIXML2_PATCH_VERSION = 6; 89 90 namespace tinyxml2 91 { 92 class XMLDocument; 93 class XMLElement; 94 class XMLAttribute; 95 class XMLComment; 96 class XMLNode; 97 class XMLText; 98 class XMLDeclaration; 99 class XMLUnknown; 100 101 class XMLPrinter; 102 103 /* 104 A class that wraps strings. Normally stores the start and end 105 pointers into the XML file itself, and will apply normalization 106 and entity translation if actually read. Can also store (and memory 107 manage) a traditional char[] 108 */ 109 class StrPair 110 { 111 public: 112 enum { 113 NEEDS_ENTITY_PROCESSING = 0x01, 114 NEEDS_NEWLINE_NORMALIZATION = 0x02, 115 116 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, 117 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, 118 ATTRIBUTE_NAME = 0, 119 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, 120 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, 121 COMMENT = NEEDS_NEWLINE_NORMALIZATION 122 }; 123 124 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {} 125 ~StrPair(); 126 127 void Set( char* _start, char* _end, int _flags ) { 128 Reset(); 129 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH; 130 } 131 const char* GetStr(); 132 bool Empty() const { return start == end; } 133 134 void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); } 135 void SetStr( const char* str, int flags=0 ); 136 137 char* ParseText( char* in, const char* endTag, int strFlags ); 138 char* ParseName( char* in ); 139 140 141 private: 142 void Reset(); 143 144 enum { 145 NEEDS_FLUSH = 0x100, 146 NEEDS_DELETE = 0x200 147 }; 148 149 // After parsing, if *end != 0, it can be set to zero. 150 int flags; 151 char* start; 152 char* end; 153 }; 154 155 156 /* 157 A dynamic array of Plain Old Data. Doesn't support constructors, etc. 158 Has a small initial memory pool, so that low or no usage will not 159 cause a call to new/delete 160 */ 161 template <class T, int INIT> 162 class DynArray 163 { 164 public: 165 DynArray< T, INIT >() 166 { 167 mem = pool; 168 allocated = INIT; 169 size = 0; 170 } 171 ~DynArray() 172 { 173 if ( mem != pool ) { 174 delete [] mem; 175 } 176 } 177 void Push( T t ) 178 { 179 EnsureCapacity( size+1 ); 180 mem[size++] = t; 181 } 182 183 T* PushArr( int count ) 184 { 185 EnsureCapacity( size+count ); 186 T* ret = &mem[size]; 187 size += count; 188 return ret; 189 } 190 T Pop() { 191 return mem[--size]; 192 } 193 void PopArr( int count ) 194 { 195 TIXMLASSERT( size >= count ); 196 size -= count; 197 } 198 199 bool Empty() const { return size == 0; } 200 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; } 201 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; } 202 int Size() const { return size; } 203 int Capacity() const { return allocated; } 204 const T* Mem() const { return mem; } 205 T* Mem() { return mem; } 206 207 208 private: 209 void EnsureCapacity( int cap ) { 210 if ( cap > allocated ) { 211 int newAllocated = cap * 2; 212 T* newMem = new T[newAllocated]; 213 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs 214 if ( mem != pool ) delete [] mem; 215 mem = newMem; 216 allocated = newAllocated; 217 } 218 } 219 220 T* mem; 221 T pool[INIT]; 222 int allocated; // objects allocated 223 int size; // number objects in use 224 }; 225 226 227 /* 228 Parent virtual class of a pool for fast allocation 229 and deallocation of objects. 230 */ 231 class MemPool 232 { 233 public: 234 MemPool() {} 235 virtual ~MemPool() {} 236 237 virtual int ItemSize() const = 0; 238 virtual void* Alloc() = 0; 239 virtual void Free( void* ) = 0; 240 }; 241 242 243 /* 244 Template child class to create pools of the correct type. 245 */ 246 template< int SIZE > 247 class MemPoolT : public MemPool 248 { 249 public: 250 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {} 251 ~MemPoolT() { 252 // Delete the blocks. 253 for( int i=0; i<blockPtrs.Size(); ++i ) { 254 delete blockPtrs[i]; 255 } 256 } 257 258 virtual int ItemSize() const { return SIZE; } 259 int CurrentAllocs() const { return currentAllocs; } 260 261 virtual void* Alloc() { 262 if ( !root ) { 263 // Need a new block. 264 Block* block = new Block(); 265 blockPtrs.Push( block ); 266 267 for( int i=0; i<COUNT-1; ++i ) { 268 block->chunk[i].next = &block->chunk[i+1]; 269 } 270 block->chunk[COUNT-1].next = 0; 271 root = block->chunk; 272 } 273 void* result = root; 274 root = root->next; 275 276 ++currentAllocs; 277 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs; 278 nAllocs++; 279 return result; 280 } 281 virtual void Free( void* mem ) { 282 if ( !mem ) return; 283 --currentAllocs; 284 Chunk* chunk = (Chunk*)mem; 285 memset( chunk, 0xfe, sizeof(Chunk) ); 286 chunk->next = root; 287 root = chunk; 288 } 289 void Trace( const char* name ) { 290 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", 291 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() ); 292 } 293 294 private: 295 enum { COUNT = 1024/SIZE }; 296 union Chunk { 297 Chunk* next; 298 char mem[SIZE]; 299 }; 300 struct Block { 301 Chunk chunk[COUNT]; 302 }; 303 DynArray< Block*, 10 > blockPtrs; 304 Chunk* root; 305 306 int currentAllocs; 307 int nAllocs; 308 int maxAllocs; 309 }; 310 311 312 313 /** 314 Implements the interface to the "Visitor pattern" (see the Accept() method.) 315 If you call the Accept() method, it requires being passed a XMLVisitor 316 class to handle callbacks. For nodes that contain other nodes (Document, Element) 317 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs 318 are simply called with Visit(). 319 320 If you return 'true' from a Visit method, recursive parsing will continue. If you return 321 false, <b>no children of this node or its sibilings</b> will be visited. 322 323 All flavors of Visit methods have a default implementation that returns 'true' (continue 324 visiting). You need to only override methods that are interesting to you. 325 326 Generally Accept() is called on the TiXmlDocument, although all nodes support visiting. 327 328 You should never change the document from a callback. 329 330 @sa XMLNode::Accept() 331 */ 332 class XMLVisitor 333 { 334 public: 335 virtual ~XMLVisitor() {} 336 337 /// Visit a document. 338 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; } 339 /// Visit a document. 340 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; } 341 342 /// Visit an element. 343 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; } 344 /// Visit an element. 345 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; } 346 347 /// Visit a declaration. 348 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; } 349 /// Visit a text node. 350 virtual bool Visit( const XMLText& /*text*/ ) { return true; } 351 /// Visit a comment node. 352 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; } 353 /// Visit an unknown node. 354 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; } 355 }; 356 357 358 /* 359 Utility functionality. 360 */ 361 class XMLUtil 362 { 363 public: 364 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't 365 // correct, but simple, and usually works. 366 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) { ++p; } return p; } 367 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) ) { ++p; } return p; } 368 369 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { 370 int n = 0; 371 if ( p == q ) { 372 return true; 373 } 374 while( *p && *q && *p == *q && n<nChar ) { 375 ++p; ++q; ++n; 376 } 377 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) { 378 return true; 379 } 380 return false; 381 } 382 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; } 383 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; } 384 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; } 385 386 static const char* ReadBOM( const char* p, bool* hasBOM ); 387 // p is the starting location, 388 // the UTF-8 value of the entity will be placed in value, and length filled in. 389 static const char* GetCharacterRef( const char* p, char* value, int* length ); 390 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); 391 392 // converts primitive types to strings 393 static void ToStr( int v, char* buffer, int bufferSize ); 394 static void ToStr( unsigned v, char* buffer, int bufferSize ); 395 static void ToStr( bool v, char* buffer, int bufferSize ); 396 static void ToStr( float v, char* buffer, int bufferSize ); 397 static void ToStr( double v, char* buffer, int bufferSize ); 398 399 // converts strings to primitive types 400 static bool ToInt( const char* str, int* value ); 401 static bool ToUnsigned( const char* str, unsigned* value ); 402 static bool ToBool( const char* str, bool* value ); 403 static bool ToFloat( const char* str, float* value ); 404 static bool ToDouble( const char* str, double* value ); 405 }; 406 407 408 /** XMLNode is a base class for every object that is in the 409 XML Document Object Model (DOM), except XMLAttributes. 410 Nodes have siblings, a parent, and children which can 411 be navigated. A node is always in a XMLDocument. 412 The type of a XMLNode can be queried, and it can 413 be cast to its more defined type. 414 415 A XMLDocument allocates memory for all its Nodes. 416 When the XMLDocument gets deleted, all its Nodes 417 will also be deleted. 418 419 @verbatim 420 A Document can contain: Element (container or leaf) 421 Comment (leaf) 422 Unknown (leaf) 423 Declaration( leaf ) 424 425 An Element can contain: Element (container or leaf) 426 Text (leaf) 427 Attributes (not on tree) 428 Comment (leaf) 429 Unknown (leaf) 430 431 @endverbatim 432 */ 433 class XMLNode 434 { 435 friend class XMLDocument; 436 friend class XMLElement; 437 public: 438 439 /// Get the XMLDocument that owns this XMLNode. 440 const XMLDocument* GetDocument() const { return document; } 441 /// Get the XMLDocument that owns this XMLNode. 442 XMLDocument* GetDocument() { return document; } 443 444 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null. 445 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null. 446 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null. 447 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null. 448 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null. 449 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null. 450 451 virtual const XMLElement* ToElement() const { return 0; } 452 virtual const XMLText* ToText() const { return 0; } 453 virtual const XMLComment* ToComment() const { return 0; } 454 virtual const XMLDocument* ToDocument() const { return 0; } 455 virtual const XMLDeclaration* ToDeclaration() const { return 0; } 456 virtual const XMLUnknown* ToUnknown() const { return 0; } 457 458 /** The meaning of 'value' changes for the specific type. 459 @verbatim 460 Document: empty 461 Element: name of the element 462 Comment: the comment text 463 Unknown: the tag contents 464 Text: the text string 465 @endverbatim 466 */ 467 const char* Value() const { return value.GetStr(); } 468 /** Set the Value of an XML node. 469 @sa Value() 470 */ 471 void SetValue( const char* val, bool staticMem=false ); 472 473 /// Get the parent of this node on the DOM. 474 const XMLNode* Parent() const { return parent; } 475 XMLNode* Parent() { return parent; } 476 477 /// Returns true if this node has no children. 478 bool NoChildren() const { return !firstChild; } 479 480 /// Get the first child node, or null if none exists. 481 const XMLNode* FirstChild() const { return firstChild; } 482 XMLNode* FirstChild() { return firstChild; } 483 /** Get the first child element, or optionally the first child 484 element with the specified name. 485 */ 486 const XMLElement* FirstChildElement( const char* value=0 ) const; 487 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); } 488 489 /// Get the last child node, or null if none exists. 490 const XMLNode* LastChild() const { return lastChild; } 491 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); } 492 493 /** Get the last child element or optionally the last child 494 element with the specified name. 495 */ 496 const XMLElement* LastChildElement( const char* value=0 ) const; 497 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); } 498 499 /// Get the previous (left) sibling node of this node. 500 const XMLNode* PreviousSibling() const { return prev; } 501 XMLNode* PreviousSibling() { return prev; } 502 503 /// Get the previous (left) sibling element of this node, with an opitionally supplied name. 504 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; 505 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); } 506 507 /// Get the next (right) sibling node of this node. 508 const XMLNode* NextSibling() const { return next; } 509 XMLNode* NextSibling() { return next; } 510 511 /// Get the next (right) sibling element of this node, with an opitionally supplied name. 512 const XMLElement* NextSiblingElement( const char* value=0 ) const; 513 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); } 514 515 /** 516 Add a child node as the last (right) child. 517 */ 518 XMLNode* InsertEndChild( XMLNode* addThis ); 519 520 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); } 521 /** 522 Add a child node as the first (left) child. 523 */ 524 XMLNode* InsertFirstChild( XMLNode* addThis ); 525 /** 526 Add a node after the specified child node. 527 */ 528 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); 529 530 /** 531 Delete all the children of this node. 532 */ 533 void DeleteChildren(); 534 535 /** 536 Delete a child of this node. 537 */ 538 void DeleteChild( XMLNode* node ); 539 540 /** 541 Make a copy of this node, but not its children. 542 You may pass in a Document pointer that will be 543 the owner of the new Node. If the 'document' is 544 null, then the node returned will be allocated 545 from the current Document. (this->GetDocument()) 546 547 Note: if called on a XMLDocument, this will return null. 548 */ 549 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; 550 551 /** 552 Test if 2 nodes are the same, but don't test children. 553 The 2 nodes do not need to be in the same Document. 554 555 Note: if called on a XMLDocument, this will return false. 556 */ 557 virtual bool ShallowEqual( const XMLNode* compare ) const = 0; 558 559 /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the 560 XML tree will be conditionally visited and the host will be called back 561 via the TiXmlVisitor interface. 562 563 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse 564 the XML for the callbacks, so the performance of TinyXML is unchanged by using this 565 interface versus any other.) 566 567 The interface has been based on ideas from: 568 569 - http://www.saxproject.org/ 570 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern 571 572 Which are both good references for "visiting". 573 574 An example of using Accept(): 575 @verbatim 576 TiXmlPrinter printer; 577 tinyxmlDoc.Accept( &printer ); 578 const char* xmlcstr = printer.CStr(); 579 @endverbatim 580 */ 581 virtual bool Accept( XMLVisitor* visitor ) const = 0; 582 583 // internal 584 virtual char* ParseDeep( char*, StrPair* ); 585 586 protected: 587 XMLNode( XMLDocument* ); 588 virtual ~XMLNode(); 589 XMLNode( const XMLNode& ); // not supported 590 XMLNode& operator=( const XMLNode& ); // not supported 591 592 XMLDocument* document; 593 XMLNode* parent; 594 mutable StrPair value; 595 596 XMLNode* firstChild; 597 XMLNode* lastChild; 598 599 XMLNode* prev; 600 XMLNode* next; 601 602 private: 603 MemPool* memPool; 604 void Unlink( XMLNode* child ); 605 }; 606 607 608 /** XML text. 609 610 Note that a text node can have child element nodes, for example: 611 @verbatim 612 <root>This is <b>bold</b></root> 613 @endverbatim 614 615 A text node can have 2 ways to output the next. "normal" output 616 and CDATA. It will default to the mode it was parsed from the XML file and 617 you generally want to leave it alone, but you can change the output mode with 618 SetCDATA() and query it with CDATA(). 619 */ 620 class XMLText : public XMLNode 621 { 622 friend class XMLBase; 623 friend class XMLDocument; 624 public: 625 virtual bool Accept( XMLVisitor* visitor ) const; 626 627 virtual XMLText* ToText() { return this; } 628 virtual const XMLText* ToText() const { return this; } 629 630 /// Declare whether this should be CDATA or standard text. 631 void SetCData( bool _isCData ) { this->isCData = _isCData; } 632 /// Returns true if this is a CDATA text element. 633 bool CData() const { return isCData; } 634 635 char* ParseDeep( char*, StrPair* endTag ); 636 virtual XMLNode* ShallowClone( XMLDocument* document ) const; 637 virtual bool ShallowEqual( const XMLNode* compare ) const; 638 639 640 protected: 641 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {} 642 virtual ~XMLText() {} 643 XMLText( const XMLText& ); // not supported 644 XMLText& operator=( const XMLText& ); // not supported 645 646 private: 647 bool isCData; 648 }; 649 650 651 /** An XML Comment. */ 652 class XMLComment : public XMLNode 653 { 654 friend class XMLDocument; 655 public: 656 virtual XMLComment* ToComment() { return this; } 657 virtual const XMLComment* ToComment() const { return this; } 658 659 virtual bool Accept( XMLVisitor* visitor ) const; 660 661 char* ParseDeep( char*, StrPair* endTag ); 662 virtual XMLNode* ShallowClone( XMLDocument* document ) const; 663 virtual bool ShallowEqual( const XMLNode* compare ) const; 664 665 protected: 666 XMLComment( XMLDocument* doc ); 667 virtual ~XMLComment(); 668 XMLComment( const XMLComment& ); // not supported 669 XMLComment& operator=( const XMLComment& ); // not supported 670 671 private: 672 }; 673 674 675 /** In correct XML the declaration is the first entry in the file. 676 @verbatim 677 <?xml version="1.0" standalone="yes"?> 678 @endverbatim 679 680 TinyXML2 will happily read or write files without a declaration, 681 however. 682 683 The text of the declaration isn't interpreted. It is parsed 684 and written as a string. 685 */ 686 class XMLDeclaration : public XMLNode 687 { 688 friend class XMLDocument; 689 public: 690 virtual XMLDeclaration* ToDeclaration() { return this; } 691 virtual const XMLDeclaration* ToDeclaration() const { return this; } 692 693 virtual bool Accept( XMLVisitor* visitor ) const; 694 695 char* ParseDeep( char*, StrPair* endTag ); 696 virtual XMLNode* ShallowClone( XMLDocument* document ) const; 697 virtual bool ShallowEqual( const XMLNode* compare ) const; 698 699 protected: 700 XMLDeclaration( XMLDocument* doc ); 701 virtual ~XMLDeclaration(); 702 XMLDeclaration( const XMLDeclaration& ); // not supported 703 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported 704 }; 705 706 707 /** Any tag that tinyXml doesn't recognize is saved as an 708 unknown. It is a tag of text, but should not be modified. 709 It will be written back to the XML, unchanged, when the file 710 is saved. 711 712 DTD tags get thrown into TiXmlUnknowns. 713 */ 714 class XMLUnknown : public XMLNode 715 { 716 friend class XMLDocument; 717 public: 718 virtual XMLUnknown* ToUnknown() { return this; } 719 virtual const XMLUnknown* ToUnknown() const { return this; } 720 721 virtual bool Accept( XMLVisitor* visitor ) const; 722 723 char* ParseDeep( char*, StrPair* endTag ); 724 virtual XMLNode* ShallowClone( XMLDocument* document ) const; 725 virtual bool ShallowEqual( const XMLNode* compare ) const; 726 727 protected: 728 XMLUnknown( XMLDocument* doc ); 729 virtual ~XMLUnknown(); 730 XMLUnknown( const XMLUnknown& ); // not supported 731 XMLUnknown& operator=( const XMLUnknown& ); // not supported 732 }; 733 734 735 enum { 736 XML_NO_ERROR = 0, 737 XML_SUCCESS = 0, 738 739 XML_NO_ATTRIBUTE, 740 XML_WRONG_ATTRIBUTE_TYPE, 741 742 XML_ERROR_FILE_NOT_FOUND, 743 XML_ERROR_FILE_COULD_NOT_BE_OPENED, 744 XML_ERROR_FILE_READ_ERROR, 745 XML_ERROR_ELEMENT_MISMATCH, 746 XML_ERROR_PARSING_ELEMENT, 747 XML_ERROR_PARSING_ATTRIBUTE, 748 XML_ERROR_IDENTIFYING_TAG, 749 XML_ERROR_PARSING_TEXT, 750 XML_ERROR_PARSING_CDATA, 751 XML_ERROR_PARSING_COMMENT, 752 XML_ERROR_PARSING_DECLARATION, 753 XML_ERROR_PARSING_UNKNOWN, 754 XML_ERROR_EMPTY_DOCUMENT, 755 XML_ERROR_MISMATCHED_ELEMENT, 756 XML_ERROR_PARSING, 757 758 XML_CAN_NOT_CONVERT_TEXT, 759 XML_NO_TEXT_NODE 760 }; 761 762 763 /** An attribute is a name-value pair. Elements have an arbitrary 764 number of attributes, each with a unique name. 765 766 @note The attributes are not XMLNodes. You may only query the 767 Next() attribute in a list. 768 */ 769 class XMLAttribute 770 { 771 friend class XMLElement; 772 public: 773 const char* Name() const { return name.GetStr(); } ///< The name of the attribute. 774 const char* Value() const { return value.GetStr(); } ///< The value of the attribute. 775 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list. 776 777 /** IntAttribute interprets the attribute as an integer, and returns the value. 778 If the value isn't an integer, 0 will be returned. There is no error checking; 779 use QueryIntAttribute() if you need error checking. 780 */ 781 int IntValue() const { int i=0; QueryIntValue( &i ); return i; } 782 /// Query as an unsigned integer. See IntAttribute() 783 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; } 784 /// Query as a boolean. See IntAttribute() 785 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; } 786 /// Query as a double. See IntAttribute() 787 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; } 788 /// Query as a float. See IntAttribute() 789 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; } 790 791 /** QueryIntAttribute interprets the attribute as an integer, and returns the value 792 in the provided paremeter. The function will return XML_NO_ERROR on success, 793 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. 794 */ 795 int QueryIntValue( int* value ) const; 796 /// See QueryIntAttribute 797 int QueryUnsignedValue( unsigned int* value ) const; 798 /// See QueryIntAttribute 799 int QueryBoolValue( bool* value ) const; 800 /// See QueryIntAttribute 801 int QueryDoubleValue( double* value ) const; 802 /// See QueryIntAttribute 803 int QueryFloatValue( float* value ) const; 804 805 /// Set the attribute to a string value. 806 void SetAttribute( const char* value ); 807 /// Set the attribute to value. 808 void SetAttribute( int value ); 809 /// Set the attribute to value. 810 void SetAttribute( unsigned value ); 811 /// Set the attribute to value. 812 void SetAttribute( bool value ); 813 /// Set the attribute to value. 814 void SetAttribute( double value ); 815 /// Set the attribute to value. 816 void SetAttribute( float value ); 817 818 private: 819 enum { BUF_SIZE = 200 }; 820 821 XMLAttribute() : next( 0 ) {} 822 virtual ~XMLAttribute() {} 823 XMLAttribute( const XMLAttribute& ); // not supported 824 void operator=( const XMLAttribute& ); // not supported 825 void SetName( const char* name ); 826 827 char* ParseDeep( char* p, bool processEntities ); 828 829 mutable StrPair name; 830 mutable StrPair value; 831 XMLAttribute* next; 832 MemPool* memPool; 833 }; 834 835 836 /** The element is a container class. It has a value, the element name, 837 and can contain other elements, text, comments, and unknowns. 838 Elements also contain an arbitrary number of attributes. 839 */ 840 class XMLElement : public XMLNode 841 { 842 friend class XMLBase; 843 friend class XMLDocument; 844 public: 845 /// Get the name of an element (which is the Value() of the node.) 846 const char* Name() const { return Value(); } 847 /// Set the name of the element. 848 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); } 849 850 virtual XMLElement* ToElement() { return this; } 851 virtual const XMLElement* ToElement() const { return this; } 852 virtual bool Accept( XMLVisitor* visitor ) const; 853 854 /** Given an attribute name, Attribute() returns the value 855 for the attribute of that name, or null if none 856 exists. For example: 857 858 @verbatim 859 const char* value = ele->Attribute( "foo" ); 860 @endverbatim 861 862 The 'value' parameter is normally null. However, if specified, 863 the attribute will only be returned if the 'name' and 'value' 864 match. This allow you to write code: 865 866 @verbatim 867 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); 868 @endverbatim 869 870 rather than: 871 @verbatim 872 if ( ele->Attribute( "foo" ) ) { 873 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); 874 } 875 @endverbatim 876 */ 877 const char* Attribute( const char* name, const char* value=0 ) const; 878 879 /** Given an attribute name, IntAttribute() returns the value 880 of the attribute interpreted as an integer. 0 will be 881 returned if there is an error. For a method with error 882 checking, see QueryIntAttribute() 883 */ 884 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; } 885 /// See IntAttribute() 886 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; } 887 /// See IntAttribute() 888 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; } 889 /// See IntAttribute() 890 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; } 891 /// See IntAttribute() 892 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; } 893 894 /** Given an attribute name, QueryIntAttribute() returns 895 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion 896 can't be performed, or XML_NO_ATTRIBUTE if the attribute 897 doesn't exist. If successful, the result of the conversion 898 will be written to 'value'. If not successful, nothing will 899 be written to 'value'. This allows you to provide default 900 value: 901 902 @verbatim 903 int value = 10; 904 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 905 @endverbatim 906 */ 907 int QueryIntAttribute( const char* name, int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryIntValue( _value ); } 908 /// See QueryIntAttribute() 909 int QueryUnsignedAttribute( const char* name, unsigned int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryUnsignedValue( _value ); } 910 /// See QueryIntAttribute() 911 int QueryBoolAttribute( const char* name, bool* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryBoolValue( _value ); } 912 /// See QueryIntAttribute() 913 int QueryDoubleAttribute( const char* name, double* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryDoubleValue( _value ); } 914 /// See QueryIntAttribute() 915 int QueryFloatAttribute( const char* name, float* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryFloatValue( _value ); } 916 917 /// Sets the named attribute to value. 918 void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); } 919 /// Sets the named attribute to value. 920 void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); } 921 /// Sets the named attribute to value. 922 void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); } 923 /// Sets the named attribute to value. 924 void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); } 925 /// Sets the named attribute to value. 926 void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); } 927 928 /** 929 Delete an attribute. 930 */ 931 void DeleteAttribute( const char* name ); 932 933 /// Return the first attribute in the list. 934 const XMLAttribute* FirstAttribute() const { return rootAttribute; } 935 /// Query a specific attribute in the list. 936 const XMLAttribute* FindAttribute( const char* name ) const; 937 938 /** Convenience function for easy access to the text inside an element. Although easy 939 and concise, GetText() is limited compared to getting the TiXmlText child 940 and accessing it directly. 941 942 If the first child of 'this' is a TiXmlText, the GetText() 943 returns the character string of the Text node, else null is returned. 944 945 This is a convenient method for getting the text of simple contained text: 946 @verbatim 947 <foo>This is text</foo> 948 const char* str = fooElement->GetText(); 949 @endverbatim 950 951 'str' will be a pointer to "This is text". 952 953 Note that this function can be misleading. If the element foo was created from 954 this XML: 955 @verbatim 956 <foo><b>This is text</b></foo> 957 @endverbatim 958 959 then the value of str would be null. The first child node isn't a text node, it is 960 another element. From this XML: 961 @verbatim 962 <foo>This is <b>text</b></foo> 963 @endverbatim 964 GetText() will return "This is ". 965 */ 966 const char* GetText() const; 967 968 /** 969 Convenience method to query the value of a child text node. This is probably best 970 shown by example. Given you have a document is this form: 971 @verbatim 972 <point> 973 <x>1</x> 974 <y>1.4</y> 975 </point> 976 @endverbatim 977 978 The QueryIntText() and similar functions provide a safe and easier way to get to the 979 "value" of x and y. 980 981 @verbatim 982 int x = 0; 983 float y = 0; // types of x and y are contrived for example 984 const XMLElement* xElement = pointElement->FirstChildElement( "x" ); 985 const XMLElement* yElement = pointElement->FirstChildElement( "y" ); 986 xElement->QueryIntText( &x ); 987 yElement->QueryFloatText( &y ); 988 @endverbatim 989 990 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted 991 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. 992 993 */ 994 int QueryIntText( int* _value ) const; 995 /// See QueryIntText() 996 int QueryUnsignedText( unsigned* _value ) const; 997 /// See QueryIntText() 998 int QueryBoolText( bool* _value ) const; 999 /// See QueryIntText() 1000 int QueryDoubleText( double* _value ) const; 1001 /// See QueryIntText() 1002 int QueryFloatText( float* _value ) const; 1003 1004 // internal: 1005 enum { 1006 OPEN, // <foo> 1007 CLOSED, // <foo/> 1008 CLOSING // </foo> 1009 }; 1010 int ClosingType() const { return closingType; } 1011 char* ParseDeep( char* p, StrPair* endTag ); 1012 virtual XMLNode* ShallowClone( XMLDocument* document ) const; 1013 virtual bool ShallowEqual( const XMLNode* compare ) const; 1014 1015 private: 1016 XMLElement( XMLDocument* doc ); 1017 virtual ~XMLElement(); 1018 XMLElement( const XMLElement& ); // not supported 1019 void operator=( const XMLElement& ); // not supported 1020 1021 XMLAttribute* FindAttribute( const char* name ); 1022 XMLAttribute* FindOrCreateAttribute( const char* name ); 1023 //void LinkAttribute( XMLAttribute* attrib ); 1024 char* ParseAttributes( char* p ); 1025 1026 int closingType; 1027 // The attribute list is ordered; there is no 'lastAttribute' 1028 // because the list needs to be scanned for dupes before adding 1029 // a new attribute. 1030 XMLAttribute* rootAttribute; 1031 }; 1032 1033 1034 /** A Document binds together all the functionality. 1035 It can be saved, loaded, and printed to the screen. 1036 All Nodes are connected and allocated to a Document. 1037 If the Document is deleted, all its Nodes are also deleted. 1038 */ 1039 class XMLDocument : public XMLNode 1040 { 1041 friend class XMLElement; 1042 public: 1043 /// constructor 1044 XMLDocument( bool processEntities = true ); 1045 ~XMLDocument(); 1046 1047 virtual XMLDocument* ToDocument() { return this; } 1048 virtual const XMLDocument* ToDocument() const { return this; } 1049 1050 /** 1051 Parse an XML file from a character string. 1052 Returns XML_NO_ERROR (0) on success, or 1053 an errorID. 1054 */ 1055 int Parse( const char* xml ); 1056 1057 /** 1058 Load an XML file from disk. 1059 Returns XML_NO_ERROR (0) on success, or 1060 an errorID. 1061 */ 1062 int LoadFile( const char* filename ); 1063 1064 /** 1065 Load an XML file from disk. You are responsible 1066 for providing and closing the FILE*. 1067 1068 Returns XML_NO_ERROR (0) on success, or 1069 an errorID. 1070 */ 1071 int LoadFile( FILE* ); 1072 1073 /** 1074 Save the XML file to disk. 1075 Returns XML_NO_ERROR (0) on success, or 1076 an errorID. 1077 */ 1078 int SaveFile( const char* filename ); 1079 1080 /** 1081 Save the XML file to disk. You are responsible 1082 for providing and closing the FILE*. 1083 1084 Returns XML_NO_ERROR (0) on success, or 1085 an errorID. 1086 */ 1087 int SaveFile( FILE* ); 1088 1089 bool ProcessEntities() const { return processEntities; } 1090 1091 /** 1092 Returns true if this document has a leading Byte Order Mark of UTF8. 1093 */ 1094 bool HasBOM() const { return writeBOM; } 1095 /** Sets whether to write the BOM when writing the file. 1096 */ 1097 void SetBOM( bool useBOM ) { writeBOM = useBOM; } 1098 1099 /** Return the root element of DOM. Equivalent to FirstChildElement(). 1100 To get the first node, use FirstChild(). 1101 */ 1102 XMLElement* RootElement() { return FirstChildElement(); } 1103 const XMLElement* RootElement() const { return FirstChildElement(); } 1104 1105 /** Print the Document. If the Printer is not provided, it will 1106 print to stdout. If you provide Printer, this can print to a file: 1107 @verbatim 1108 XMLPrinter printer( fp ); 1109 doc.Print( &printer ); 1110 @endverbatim 1111 1112 Or you can use a printer to print to memory: 1113 @verbatim 1114 XMLPrinter printer; 1115 doc->Print( &printer ); 1116 // printer.CStr() has a const char* to the XML 1117 @endverbatim 1118 */ 1119 void Print( XMLPrinter* streamer=0 ); 1120 virtual bool Accept( XMLVisitor* visitor ) const; 1121 1122 /** 1123 Create a new Element associated with 1124 this Document. The memory for the Element 1125 is managed by the Document. 1126 */ 1127 XMLElement* NewElement( const char* name ); 1128 /** 1129 Create a new Comment associated with 1130 this Document. The memory for the Comment 1131 is managed by the Document. 1132 */ 1133 XMLComment* NewComment( const char* comment ); 1134 /** 1135 Create a new Text associated with 1136 this Document. The memory for the Text 1137 is managed by the Document. 1138 */ 1139 XMLText* NewText( const char* text ); 1140 /** 1141 Create a new Declaration associated with 1142 this Document. The memory for the object 1143 is managed by the Document. 1144 1145 If the 'text' param is null, the standard 1146 declaration is used.: 1147 @verbatim 1148 <?xml version="1.0" encoding="UTF-8"?> 1149 @endverbatim 1150 */ 1151 XMLDeclaration* NewDeclaration( const char* text=0 ); 1152 /** 1153 Create a new Unknown associated with 1154 this Document. The memory for the object 1155 is managed by the Document. 1156 */ 1157 XMLUnknown* NewUnknown( const char* text ); 1158 1159 /** 1160 Delete a node associated with this document. 1161 It will be unlinked from the DOM. 1162 */ 1163 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); } 1164 1165 void SetError( int error, const char* str1, const char* str2 ); 1166 1167 /// Return true if there was an error parsing the document. 1168 bool Error() const { return errorID != XML_NO_ERROR; } 1169 /// Return the errorID. 1170 int ErrorID() const { return errorID; } 1171 /// Return a possibly helpful diagnostic location or string. 1172 const char* GetErrorStr1() const { return errorStr1; } 1173 /// Return a possibly helpful secondary diagnostic location or string. 1174 const char* GetErrorStr2() const { return errorStr2; } 1175 /// If there is an error, print it to stdout. 1176 void PrintError() const; 1177 1178 // internal 1179 char* Identify( char* p, XMLNode** node ); 1180 1181 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; } 1182 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; } 1183 1184 private: 1185 XMLDocument( const XMLDocument& ); // not supported 1186 void operator=( const XMLDocument& ); // not supported 1187 void InitDocument(); 1188 1189 bool writeBOM; 1190 bool processEntities; 1191 int errorID; 1192 const char* errorStr1; 1193 const char* errorStr2; 1194 char* charBuffer; 1195 1196 MemPoolT< sizeof(XMLElement) > elementPool; 1197 MemPoolT< sizeof(XMLAttribute) > attributePool; 1198 MemPoolT< sizeof(XMLText) > textPool; 1199 MemPoolT< sizeof(XMLComment) > commentPool; 1200 }; 1201 1202 1203 /** 1204 A XMLHandle is a class that wraps a node pointer with null checks; this is 1205 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML 1206 DOM structure. It is a separate utility class. 1207 1208 Take an example: 1209 @verbatim 1210 <Document> 1211 <Element attributeA = "valueA"> 1212 <Child attributeB = "value1" /> 1213 <Child attributeB = "value2" /> 1214 </Element> 1215 </Document> 1216 @endverbatim 1217 1218 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 1219 easy to write a *lot* of code that looks like: 1220 1221 @verbatim 1222 XMLElement* root = document.FirstChildElement( "Document" ); 1223 if ( root ) 1224 { 1225 XMLElement* element = root->FirstChildElement( "Element" ); 1226 if ( element ) 1227 { 1228 XMLElement* child = element->FirstChildElement( "Child" ); 1229 if ( child ) 1230 { 1231 XMLElement* child2 = child->NextSiblingElement( "Child" ); 1232 if ( child2 ) 1233 { 1234 // Finally do something useful. 1235 @endverbatim 1236 1237 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity 1238 of such code. A XMLHandle checks for null pointers so it is perfectly safe 1239 and correct to use: 1240 1241 @verbatim 1242 XMLHandle docHandle( &document ); 1243 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement(); 1244 if ( child2 ) 1245 { 1246 // do something useful 1247 @endverbatim 1248 1249 Which is MUCH more concise and useful. 1250 1251 It is also safe to copy handles - internally they are nothing more than node pointers. 1252 @verbatim 1253 XMLHandle handleCopy = handle; 1254 @endverbatim 1255 1256 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. 1257 */ 1258 class XMLHandle 1259 { 1260 public: 1261 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. 1262 XMLHandle( XMLNode* _node ) { node = _node; } 1263 /// Create a handle from a node. 1264 XMLHandle( XMLNode& _node ) { node = &_node; } 1265 /// Copy constructor 1266 XMLHandle( const XMLHandle& ref ) { node = ref.node; } 1267 /// Assignment 1268 XMLHandle& operator=( const XMLHandle& ref ) { node = ref.node; return *this; } 1269 1270 /// Get the first child of this handle. 1271 XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); } 1272 /// Get the first child element of this handle. 1273 XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); } 1274 /// Get the last child of this handle. 1275 XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); } 1276 /// Get the last child element of this handle. 1277 XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); } 1278 /// Get the previous sibling of this handle. 1279 XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); } 1280 /// Get the previous sibling element of this handle. 1281 XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); } 1282 /// Get the next sibling of this handle. 1283 XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); } 1284 /// Get the next sibling element of this handle. 1285 XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); } 1286 1287 /// Safe cast to XMLNode. This can return null. 1288 XMLNode* ToNode() { return node; } 1289 /// Safe cast to XMLElement. This can return null. 1290 XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } 1291 /// Safe cast to XMLText. This can return null. 1292 XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } 1293 /// Safe cast to XMLUnknown. This can return null. 1294 XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } 1295 /// Safe cast to XMLDeclaration. This can return null. 1296 XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); } 1297 1298 private: 1299 XMLNode* node; 1300 }; 1301 1302 1303 /** 1304 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the 1305 same in all regards, except for the 'const' qualifiers. See XMLHandle for API. 1306 */ 1307 class XMLConstHandle 1308 { 1309 public: 1310 XMLConstHandle( const XMLNode* _node ) { node = _node; } 1311 XMLConstHandle( const XMLNode& _node ) { node = &_node; } 1312 XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; } 1313 1314 XMLConstHandle& operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; } 1315 1316 const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); } 1317 const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); } 1318 const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); } 1319 const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); } 1320 const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); } 1321 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); } 1322 const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); } 1323 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); } 1324 1325 1326 const XMLNode* ToNode() const { return node; } 1327 const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } 1328 const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } 1329 const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } 1330 const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); } 1331 1332 private: 1333 const XMLNode* node; 1334 }; 1335 1336 1337 /** 1338 Printing functionality. The XMLPrinter gives you more 1339 options than the XMLDocument::Print() method. 1340 1341 It can: 1342 -# Print to memory. 1343 -# Print to a file you provide. 1344 -# Print XML without a XMLDocument. 1345 1346 Print to Memory 1347 1348 @verbatim 1349 XMLPrinter printer; 1350 doc->Print( &printer ); 1351 SomeFunction( printer.CStr() ); 1352 @endverbatim 1353 1354 Print to a File 1355 1356 You provide the file pointer. 1357 @verbatim 1358 XMLPrinter printer( fp ); 1359 doc.Print( &printer ); 1360 @endverbatim 1361 1362 Print without a XMLDocument 1363 1364 When loading, an XML parser is very useful. However, sometimes 1365 when saving, it just gets in the way. The code is often set up 1366 for streaming, and constructing the DOM is just overhead. 1367 1368 The Printer supports the streaming case. The following code 1369 prints out a trivially simple XML file without ever creating 1370 an XML document. 1371 1372 @verbatim 1373 XMLPrinter printer( fp ); 1374 printer.OpenElement( "foo" ); 1375 printer.PushAttribute( "foo", "bar" ); 1376 printer.CloseElement(); 1377 @endverbatim 1378 */ 1379 class XMLPrinter : public XMLVisitor 1380 { 1381 public: 1382 /** Construct the printer. If the FILE* is specified, 1383 this will print to the FILE. Else it will print 1384 to memory, and the result is available in CStr(). 1385 If 'compact' is set to true, then output is created 1386 with only required whitespace and newlines. 1387 */ 1388 XMLPrinter( FILE* file=0, bool compact = false ); 1389 ~XMLPrinter() {} 1390 1391 /** If streaming, write the BOM and declaration. */ 1392 void PushHeader( bool writeBOM, bool writeDeclaration ); 1393 /** If streaming, start writing an element. 1394 The element must be closed with CloseElement() 1395 */ 1396 void OpenElement( const char* name ); 1397 /// If streaming, add an attribute to an open element. 1398 void PushAttribute( const char* name, const char* value ); 1399 void PushAttribute( const char* name, int value ); 1400 void PushAttribute( const char* name, unsigned value ); 1401 void PushAttribute( const char* name, bool value ); 1402 void PushAttribute( const char* name, double value ); 1403 /// If streaming, close the Element. 1404 void CloseElement(); 1405 1406 /// Add a text node. 1407 void PushText( const char* text, bool cdata=false ); 1408 /// Add a text node from an integer. 1409 void PushText( int value ); 1410 /// Add a text node from an unsigned. 1411 void PushText( unsigned value ); 1412 /// Add a text node from a bool. 1413 void PushText( bool value ); 1414 /// Add a text node from a float. 1415 void PushText( float value ); 1416 /// Add a text node from a double. 1417 void PushText( double value ); 1418 1419 /// Add a comment 1420 void PushComment( const char* comment ); 1421 1422 void PushDeclaration( const char* value ); 1423 void PushUnknown( const char* value ); 1424 1425 virtual bool VisitEnter( const XMLDocument& /*doc*/ ); 1426 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; } 1427 1428 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); 1429 virtual bool VisitExit( const XMLElement& element ); 1430 1431 virtual bool Visit( const XMLText& text ); 1432 virtual bool Visit( const XMLComment& comment ); 1433 virtual bool Visit( const XMLDeclaration& declaration ); 1434 virtual bool Visit( const XMLUnknown& unknown ); 1435 1436 /** 1437 If in print to memory mode, return a pointer to 1438 the XML file in memory. 1439 */ 1440 const char* CStr() const { return buffer.Mem(); } 1441 /** 1442 If in print to memory mode, return the size 1443 of the XML file in memory. (Note the size returned 1444 includes the terminating null.) 1445 */ 1446 int CStrSize() const { return buffer.Size(); } 1447 1448 private: 1449 void SealElement(); 1450 void PrintSpace( int depth ); 1451 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. 1452 void Print( const char* format, ... ); 1453 1454 bool elementJustOpened; 1455 bool firstElement; 1456 FILE* fp; 1457 int depth; 1458 int textDepth; 1459 bool processEntities; 1460 bool compactMode; 1461 1462 enum { 1463 ENTITY_RANGE = 64, 1464 BUF_SIZE = 200 1465 }; 1466 bool entityFlag[ENTITY_RANGE]; 1467 bool restrictedEntityFlag[ENTITY_RANGE]; 1468 1469 DynArray< const char*, 10 > stack; 1470 DynArray< char, 20 > buffer; 1471 #ifdef _MSC_VER 1472 DynArray< char, 20 > accumulator; 1473 #endif 1474 }; 1475 1476 1477 } // tinyxml2 1478 1479 1480 #endif // TINYXML2_INCLUDED 1481