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