1 /* 2 www.sourceforge.net/projects/tinyxml 3 Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any 7 damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any 10 purpose, including commercial applications, and to alter it and 11 redistribute it freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must 14 not claim that you wrote the original software. If you use this 15 software in a product, an acknowledgment in the product documentation 16 would be appreciated but is not required. 17 18 2. Altered source versions must be plainly marked as such, and 19 must not be misrepresented as being the original software. 20 21 3. This notice may not be removed or altered from any source 22 distribution. 23 */ 24 25 26 #ifndef TINYXML_INCLUDED 27 #define TINYXML_INCLUDED 28 29 #ifdef _MSC_VER 30 #pragma warning( disable : 4530 ) 31 #pragma warning( disable : 4786 ) 32 #endif 33 34 #include <ctype.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <assert.h> 39 40 #include "cal3d/platform.h" 41 42 // Help out windows: 43 #if defined( _DEBUG ) && !defined( DEBUG ) 44 #define DEBUG 45 #endif 46 47 #if defined( DEBUG ) && defined( _MSC_VER ) 48 #include <windows.h> 49 #define TIXML_LOG OutputDebugString 50 #else 51 #define TIXML_LOG printf 52 #endif 53 54 #define TIXML_USE_STL 55 56 #ifdef TIXML_USE_STL 57 #include <string> 58 #include <iostream> 59 #define TIXML_STRING std::string 60 #define TIXML_ISTREAM std::istream 61 #define TIXML_OSTREAM std::ostream 62 #else 63 #include "tinystr.h" 64 #define TIXML_STRING TiXmlString 65 #define TIXML_OSTREAM TiXmlOutStream 66 #endif 67 68 namespace cal3d 69 { 70 71 class TiXmlDocument; 72 class TiXmlElement; 73 class TiXmlComment; 74 class TiXmlUnknown; 75 class TiXmlAttribute; 76 class TiXmlText; 77 class TiXmlDeclaration; 78 79 class TiXmlParsingData; 80 81 /* Internal structure for tracking location of items 82 in the XML file. 83 */ 84 struct CAL3D_API TiXmlCursor 85 { TiXmlCursorTiXmlCursor86 TiXmlCursor() { Clear(); } ClearTiXmlCursor87 void Clear() { row = col = -1; } 88 89 int row; // 0 based. 90 int col; // 0 based. 91 }; 92 93 94 // Only used by Attribute::Query functions 95 enum 96 { 97 TIXML_SUCCESS, 98 TIXML_NO_ATTRIBUTE, 99 TIXML_WRONG_TYPE 100 }; 101 102 /** TiXmlBase is a base class for every class in TinyXml. 103 It does little except to establish that TinyXml classes 104 can be printed and provide some utility functions. 105 106 In XML, the document and elements can contain 107 other elements and other types of nodes. 108 109 @verbatim 110 A Document can contain: Element (container or leaf) 111 Comment (leaf) 112 Unknown (leaf) 113 Declaration( leaf ) 114 115 An Element can contain: Element (container or leaf) 116 Text (leaf) 117 Attributes (not on tree) 118 Comment (leaf) 119 Unknown (leaf) 120 121 A Decleration contains: Attributes (not on tree) 122 @endverbatim 123 */ 124 class CAL3D_API TiXmlBase 125 { 126 friend class TiXmlNode; 127 friend class TiXmlElement; 128 friend class TiXmlDocument; 129 130 public: TiXmlBase()131 TiXmlBase() {} ~TiXmlBase()132 virtual ~TiXmlBase() {} 133 134 /** All TinyXml classes can print themselves to a filestream. 135 This is a formatted print, and will insert tabs and newlines. 136 137 (For an unformatted stream, use the << operator.) 138 */ 139 virtual void Print( FILE* cfile, int depth ) const = 0; 140 141 /** The world does not agree on whether white space should be kept or 142 not. In order to make everyone happy, these global, static functions 143 are provided to set whether or not TinyXml will condense all white space 144 into a single space or not. The default is to condense. Note changing this 145 values is not thread safe. 146 */ SetCondenseWhiteSpace(bool condense)147 static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } 148 149 /// Return the current white space setting. IsWhiteSpaceCondensed()150 static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } 151 152 /** Return the position, in the original source file, of this node or attribute. 153 The row and column are 1-based. (That is the first row and first column is 154 1,1). If the returns values are 0 or less, then the parser does not have 155 a row and column value. 156 157 Generally, the row and column value will be set when the TiXmlDocument::Load(), 158 TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set 159 when the DOM was created from operator>>. 160 161 The values reflect the initial load. Once the DOM is modified programmatically 162 (by adding or changing nodes and attributes) the new values will NOT update to 163 reflect changes in the document. 164 165 There is a minor performance cost to computing the row and column. Computation 166 can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. 167 168 @sa TiXmlDocument::SetTabSize() 169 */ Row()170 int Row() const { return location.row + 1; } Column()171 int Column() const { return location.col + 1; } ///< See Row() 172 173 protected: 174 // See STL_STRING_BUG 175 // Utility class to overcome a bug. 176 class StringToBuffer 177 { 178 public: 179 StringToBuffer( const TIXML_STRING& str ); 180 ~StringToBuffer(); 181 char* buffer; 182 }; 183 184 static const char* SkipWhiteSpace( const char* ); IsWhiteSpace(int c)185 inline static bool IsWhiteSpace( int c ) { return ( isspace( c ) || c == '\n' || c == '\r' ); } 186 187 virtual void StreamOut (TIXML_OSTREAM *) const = 0; 188 189 #ifdef TIXML_USE_STL 190 static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); 191 static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); 192 #endif 193 194 /* Reads an XML name into the string provided. Returns 195 a pointer just past the last character of the name, 196 or 0 if the function has an error. 197 */ 198 static const char* ReadName( const char* p, TIXML_STRING* name ); 199 200 /* Reads text. Returns a pointer past the given end tag. 201 Wickedly complex options, but it keeps the (sensitive) code in one place. 202 */ 203 static const char* ReadText( const char* in, // where to start 204 TIXML_STRING* text, // the string read 205 bool ignoreWhiteSpace, // whether to keep the white space 206 const char* endTag, // what ends this text 207 bool ignoreCase ); // whether to ignore case in the end tag 208 209 virtual const char* Parse( const char* p, TiXmlParsingData* data ) = 0; 210 211 // If an entity has been found, transform it into a character. 212 static const char* GetEntity( const char* in, char* value ); 213 214 // Get a character, while interpreting entities. GetChar(const char * p,char * _value)215 inline static const char* GetChar( const char* p, char* _value ) 216 { 217 assert( p ); 218 if ( *p == '&' ) 219 { 220 return GetEntity( p, _value ); 221 } 222 else 223 { 224 *_value = *p; 225 return p+1; 226 } 227 } 228 229 // Puts a string to a stream, expanding entities as it goes. 230 // Note this should not contian the '<', '>', etc, or they will be transformed into entities! 231 static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); 232 233 static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); 234 235 // Return true if the next characters in the stream are any of the endTag sequences. 236 static bool StringEqual( const char* p, 237 const char* endTag, 238 bool ignoreCase ); 239 240 241 enum 242 { 243 TIXML_NO_ERROR = 0, 244 TIXML_ERROR, 245 TIXML_ERROR_OPENING_FILE, 246 TIXML_ERROR_OUT_OF_MEMORY, 247 TIXML_ERROR_PARSING_ELEMENT, 248 TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, 249 TIXML_ERROR_READING_ELEMENT_VALUE, 250 TIXML_ERROR_READING_ATTRIBUTES, 251 TIXML_ERROR_PARSING_EMPTY, 252 TIXML_ERROR_READING_END_TAG, 253 TIXML_ERROR_PARSING_UNKNOWN, 254 TIXML_ERROR_PARSING_COMMENT, 255 TIXML_ERROR_PARSING_DECLARATION, 256 TIXML_ERROR_DOCUMENT_EMPTY, 257 258 TIXML_ERROR_STRING_COUNT 259 }; 260 static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; 261 262 TiXmlCursor location; 263 264 private: 265 struct Entity 266 { 267 const char* str; 268 unsigned int strLength; 269 char chr; 270 }; 271 enum 272 { 273 NUM_ENTITY = 5, 274 MAX_ENTITY_LENGTH = 6 275 276 }; 277 static Entity entity[ NUM_ENTITY ]; 278 static bool condenseWhiteSpace; 279 }; 280 281 282 /** The parent class for everything in the Document Object Model. 283 (Except for attributes). 284 Nodes have siblings, a parent, and children. A node can be 285 in a document, or stand on its own. The type of a TiXmlNode 286 can be queried, and it can be cast to its more defined type. 287 */ 288 class CAL3D_API TiXmlNode : public TiXmlBase 289 { 290 friend class TiXmlDocument; 291 friend class TiXmlElement; 292 293 public: 294 #ifdef TIXML_USE_STL 295 296 /** An input stream operator, for every class. Tolerant of newlines and 297 formatting, but doesn't expect them. 298 */ 299 friend std::istream& operator >> (std::istream& in, TiXmlNode& base); 300 301 /** An output stream operator, for every class. Note that this outputs 302 without any newlines or formatting, as opposed to Print(), which 303 includes tabs and new lines. 304 305 The operator<< and operator>> are not completely symmetric. Writing 306 a node to a stream is very well defined. You'll get a nice stream 307 of output, without any extra whitespace or newlines. 308 309 But reading is not as well defined. (As it always is.) If you create 310 a TiXmlElement (for example) and read that from an input stream, 311 the text needs to define an element or junk will result. This is 312 true of all input streams, but it's worth keeping in mind. 313 314 A TiXmlDocument will read nodes until it reads a root element, and 315 all the children of that root element. 316 */ 317 friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); 318 319 /// Appends the XML node or attribute to a std::string. 320 friend std::string& operator<< (std::string& out, const TiXmlNode& base ); 321 322 #else 323 // Used internally, not part of the public API. 324 friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); 325 #endif 326 327 /** The types of XML nodes supported by TinyXml. (All the 328 unsupported types are picked up by UNKNOWN.) 329 */ 330 enum NodeType 331 { 332 DOCUMENT, 333 ELEMENT, 334 COMMENT, 335 UNKNOWN, 336 TEXT, 337 DECLARATION, 338 TYPECOUNT 339 }; 340 341 virtual ~TiXmlNode(); 342 343 /** The meaning of 'value' changes for the specific type of 344 TiXmlNode. 345 @verbatim 346 Document: filename of the xml file 347 Element: name of the element 348 Comment: the comment text 349 Unknown: the tag contents 350 Text: the text string 351 @endverbatim 352 353 The subclasses will wrap this function. 354 */ Value()355 const char * Value() const { return value.c_str (); } 356 357 /** Changes the value of the node. Defined as: 358 @verbatim 359 Document: filename of the xml file 360 Element: name of the element 361 Comment: the comment text 362 Unknown: the tag contents 363 Text: the text string 364 @endverbatim 365 */ SetValue(const char * _value)366 void SetValue(const char * _value) { value = _value;} 367 368 #ifdef TIXML_USE_STL 369 /// STL std::string form. SetValue(const std::string & _value)370 void SetValue( const std::string& _value ) 371 { 372 StringToBuffer buf( _value ); 373 SetValue( buf.buffer ? buf.buffer : "" ); 374 } 375 #endif 376 377 /// Delete all the children of this node. Does not affect 'this'. 378 void Clear(); 379 380 /// One step up the DOM. Parent()381 TiXmlNode* Parent() const { return parent; } 382 FirstChild()383 TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. 384 TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. 385 LastChild()386 TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. 387 TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. 388 389 #ifdef TIXML_USE_STL FirstChild(const std::string & _value)390 TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. LastChild(const std::string & _value)391 TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. 392 #endif 393 394 /** An alternate way to walk the children of a node. 395 One way to iterate over nodes is: 396 @verbatim 397 for( child = parent->FirstChild(); child; child = child->NextSibling() ) 398 @endverbatim 399 400 IterateChildren does the same thing with the syntax: 401 @verbatim 402 child = 0; 403 while( child = parent->IterateChildren( child ) ) 404 @endverbatim 405 406 IterateChildren takes the previous child as input and finds 407 the next one. If the previous child is null, it returns the 408 first. IterateChildren will return null when done. 409 */ 410 TiXmlNode* IterateChildren( TiXmlNode* previous ) const; 411 412 /// This flavor of IterateChildren searches for children with a particular 'value' 413 TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; 414 415 #ifdef TIXML_USE_STL IterateChildren(const std::string & _value,TiXmlNode * previous)416 TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. 417 #endif 418 419 /** Add a new node related to this. Adds a child past the LastChild. 420 Returns a pointer to the new object or NULL if an error occured. 421 */ 422 TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); 423 424 425 /** Add a new node related to this. Adds a child past the LastChild. 426 427 NOTE: the node to be added is passed by pointer, and will be 428 henceforth owned (and deleted) by tinyXml. This method is efficient 429 and avoids an extra copy, but should be used with care as it 430 uses a different memory model than the other insert functions. 431 432 @sa InsertEndChild 433 */ 434 TiXmlNode* LinkEndChild( TiXmlNode* addThis ); 435 436 /** Add a new node related to this. Adds a child before the specified child. 437 Returns a pointer to the new object or NULL if an error occured. 438 */ 439 TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); 440 441 /** Add a new node related to this. Adds a child after the specified child. 442 Returns a pointer to the new object or NULL if an error occured. 443 */ 444 TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); 445 446 /** Replace a child of this node. 447 Returns a pointer to the new object or NULL if an error occured. 448 */ 449 TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); 450 451 /// Delete a child of this node. 452 bool RemoveChild( TiXmlNode* removeThis ); 453 454 /// Navigate to a sibling node. PreviousSibling()455 TiXmlNode* PreviousSibling() const { return prev; } 456 457 /// Navigate to a sibling node. 458 TiXmlNode* PreviousSibling( const char * ) const; 459 460 #ifdef TIXML_USE_STL PreviousSibling(const std::string & _value)461 TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. NextSibling(const std::string & _value)462 TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. 463 #endif 464 465 /// Navigate to a sibling node. NextSibling()466 TiXmlNode* NextSibling() const { return next; } 467 468 /// Navigate to a sibling node with the given 'value'. 469 TiXmlNode* NextSibling( const char * ) const; 470 471 /** Convenience function to get through elements. 472 Calls NextSibling and ToElement. Will skip all non-Element 473 nodes. Returns 0 if there is not another element. 474 */ 475 TiXmlElement* NextSiblingElement() const; 476 477 /** Convenience function to get through elements. 478 Calls NextSibling and ToElement. Will skip all non-Element 479 nodes. Returns 0 if there is not another element. 480 */ 481 TiXmlElement* NextSiblingElement( const char * ) const; 482 483 #ifdef TIXML_USE_STL NextSiblingElement(const std::string & _value)484 TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. 485 #endif 486 487 /// Convenience function to get through elements. 488 TiXmlElement* FirstChildElement() const; 489 490 /// Convenience function to get through elements. 491 TiXmlElement* FirstChildElement( const char * value ) const; 492 493 #ifdef TIXML_USE_STL FirstChildElement(const std::string & _value)494 TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. 495 #endif 496 497 /** Query the type (as an enumerated value, above) of this node. 498 The possible types are: DOCUMENT, ELEMENT, COMMENT, 499 UNKNOWN, TEXT, and DECLARATION. 500 */ Type()501 virtual int Type() const { return type; } 502 503 /** Return a pointer to the Document this node lives in. 504 Returns null if not in a document. 505 */ 506 TiXmlDocument* GetDocument() const; 507 508 /// Returns true if this node has no children. NoChildren()509 bool NoChildren() const { return !firstChild; } 510 ToDocument()511 TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ToElement()512 TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ToComment()513 TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ToUnknown()514 TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ToText()515 TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. ToDeclaration()516 TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. 517 518 virtual TiXmlNode* Clone() const = 0; 519 SetUserData(void * user)520 void SetUserData( void* user ) { userData = user; } GetUserData()521 void* GetUserData() { return userData; } 522 523 protected: 524 TiXmlNode( NodeType type ); 525 526 #ifdef TIXML_USE_STL 527 // The real work of the input operator. 528 virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; 529 #endif 530 531 // Figure out what is at *p, and parse it. Returns null if it is not an xml node. 532 TiXmlNode* Identify( const char* start ); CopyToClone(TiXmlNode * target)533 void CopyToClone( TiXmlNode* target ) const { target->SetValue (value.c_str() ); 534 target->userData = userData; } 535 536 // Internal Value function returning a TIXML_STRING SValue()537 TIXML_STRING SValue() const { return value ; } 538 539 TiXmlNode* parent; 540 NodeType type; 541 542 TiXmlNode* firstChild; 543 TiXmlNode* lastChild; 544 545 TIXML_STRING value; 546 547 TiXmlNode* prev; 548 TiXmlNode* next; 549 void* userData; 550 }; 551 552 553 /** An attribute is a name-value pair. Elements have an arbitrary 554 number of attributes, each with a unique name. 555 556 @note The attributes are not TiXmlNodes, since they are not 557 part of the tinyXML document object model. There are other 558 suggested ways to look at this problem. 559 */ 560 class CAL3D_API TiXmlAttribute : public TiXmlBase 561 { 562 friend class TiXmlAttributeSet; 563 564 public: 565 /// Construct an empty attribute. TiXmlAttribute()566 TiXmlAttribute() 567 { 568 document = 0; 569 prev = next = 0; 570 } 571 572 #ifdef TIXML_USE_STL 573 /// std::string constructor. TiXmlAttribute(const std::string & _name,const std::string & _value)574 TiXmlAttribute( const std::string& _name, const std::string& _value ) 575 { 576 name = _name; 577 value = _value; 578 document = 0; 579 prev = next = 0; 580 } 581 #endif 582 583 /// Construct an attribute with a name and value. TiXmlAttribute(const char * _name,const char * _value)584 TiXmlAttribute( const char * _name, const char * _value ) 585 { 586 name = _name; 587 value = _value; 588 document = 0; 589 prev = next = 0; 590 } 591 Name()592 const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. Value()593 const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. 594 const int IntValue() const; ///< Return the value of this attribute, converted to an integer. 595 const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. 596 597 /** QueryIntValue examines the value string. It is an alternative to the 598 IntValue() method with richer error checking. 599 If the value is an integer, it is stored in 'value' and 600 the call returns TIXML_SUCCESS. If it is not 601 an integer, it returns TIXML_WRONG_TYPE. 602 603 A specialized but useful call. Note that for success it returns 0, 604 which is the opposite of almost all other TinyXml calls. 605 */ 606 int QueryIntValue( int* value ) const; 607 /// QueryDoubleValue examines the value string. See QueryIntValue(). 608 int QueryDoubleValue( double* value ) const; 609 SetName(const char * _name)610 void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. SetValue(const char * _value)611 void SetValue( const char* _value ) { value = _value; } ///< Set the value. 612 613 void SetIntValue( int value ); ///< Set the value from an integer. 614 void SetDoubleValue( double value ); ///< Set the value from a double. 615 616 #ifdef TIXML_USE_STL 617 /// STL std::string form. SetName(const std::string & _name)618 void SetName( const std::string& _name ) 619 { 620 StringToBuffer buf( _name ); 621 SetName ( buf.buffer ? buf.buffer : "error" ); 622 } 623 /// STL std::string form. SetValue(const std::string & _value)624 void SetValue( const std::string& _value ) 625 { 626 StringToBuffer buf( _value ); 627 SetValue( buf.buffer ? buf.buffer : "error" ); 628 } 629 #endif 630 631 /// Get the next sibling attribute in the DOM. Returns null at end. 632 TiXmlAttribute* Next() const; 633 /// Get the previous sibling attribute in the DOM. Returns null at beginning. 634 TiXmlAttribute* Previous() const; 635 636 bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } 637 bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } 638 bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } 639 640 /* [internal use] 641 Attribtue parsing starts: first letter of the name 642 returns: the next char after the value end quote 643 */ 644 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 645 646 // [internal use] 647 virtual void Print( FILE* cfile, int depth ) const; 648 649 virtual void StreamOut( TIXML_OSTREAM * out ) const; 650 // [internal use] 651 // Set the document pointer so the attribute can report errors. SetDocument(TiXmlDocument * doc)652 void SetDocument( TiXmlDocument* doc ) { document = doc; } 653 654 private: 655 TiXmlDocument* document; // A pointer back to a document, for error reporting. 656 TIXML_STRING name; 657 TIXML_STRING value; 658 TiXmlAttribute* prev; 659 TiXmlAttribute* next; 660 }; 661 662 663 /* A class used to manage a group of attributes. 664 It is only used internally, both by the ELEMENT and the DECLARATION. 665 666 The set can be changed transparent to the Element and Declaration 667 classes that use it, but NOT transparent to the Attribute 668 which has to implement a next() and previous() method. Which makes 669 it a bit problematic and prevents the use of STL. 670 671 This version is implemented with circular lists because: 672 - I like circular lists 673 - it demonstrates some independence from the (typical) doubly linked list. 674 */ 675 class CAL3D_API TiXmlAttributeSet 676 { 677 public: 678 TiXmlAttributeSet(); 679 ~TiXmlAttributeSet(); 680 681 void Add( TiXmlAttribute* attribute ); 682 void Remove( TiXmlAttribute* attribute ); 683 First()684 TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } Last()685 TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } 686 TiXmlAttribute* Find( const char * name ) const; 687 688 private: 689 TiXmlAttribute sentinel; 690 }; 691 692 693 /** The element is a container class. It has a value, the element name, 694 and can contain other elements, text, comments, and unknowns. 695 Elements also contain an arbitrary number of attributes. 696 */ 697 class CAL3D_API TiXmlElement : public TiXmlNode 698 { 699 public: 700 /// Construct an element. 701 TiXmlElement (const char * in_value); 702 703 #ifdef TIXML_USE_STL 704 /// std::string constructor. TiXmlElement(const std::string & _value)705 TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::ELEMENT ) 706 { 707 firstChild = lastChild = 0; 708 value = _value; 709 } 710 #endif 711 712 virtual ~TiXmlElement(); 713 714 /** Given an attribute name, Attribute() returns the value 715 for the attribute of that name, or null if none exists. 716 */ 717 const char* Attribute( const char* name ) const; 718 719 /** Given an attribute name, Attribute() returns the value 720 for the attribute of that name, or null if none exists. 721 If the attribute exists and can be converted to an integer, 722 the integer value will be put in the return 'i', if 'i' 723 is non-null. 724 */ 725 const char* Attribute( const char* name, int* i ) const; 726 727 /** Given an attribute name, Attribute() returns the value 728 for the attribute of that name, or null if none exists. 729 If the attribute exists and can be converted to an double, 730 the double value will be put in the return 'd', if 'd' 731 is non-null. 732 */ 733 const char* Attribute( const char* name, double* d ) const; 734 735 /** QueryIntAttribute examines the attribute - it is an alternative to the 736 Attribute() method with richer error checking. 737 If the attribute is an integer, it is stored in 'value' and 738 the call returns TIXML_SUCCESS. If it is not 739 an integer, it returns TIXML_WRONG_TYPE. If the attribute 740 does not exist, then TIXML_NO_ATTRIBUTE is returned. 741 */ 742 int QueryIntAttribute( const char* name, int* value ) const; 743 /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). 744 int QueryDoubleAttribute( const char* name, double* value ) const; 745 746 /** Sets an attribute of name to a given value. The attribute 747 will be created if it does not exist, or changed if it does. 748 */ 749 void SetAttribute( const char* name, const char * value ); 750 751 #ifdef TIXML_USE_STL Attribute(const std::string & name)752 const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } Attribute(const std::string & name,int * i)753 const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } 754 755 /// STL std::string form. SetAttribute(const std::string & name,const std::string & _value)756 void SetAttribute( const std::string& name, const std::string& _value ) 757 { 758 StringToBuffer n( name ); 759 StringToBuffer v( _value ); 760 if ( n.buffer && v.buffer ) 761 SetAttribute (n.buffer, v.buffer ); 762 } 763 ///< STL std::string form. SetAttribute(const std::string & name,int _value)764 void SetAttribute( const std::string& name, int _value ) 765 { 766 StringToBuffer n( name ); 767 if ( n.buffer ) 768 SetAttribute (n.buffer, _value); 769 } 770 #endif 771 772 /** Sets an attribute of name to a given value. The attribute 773 will be created if it does not exist, or changed if it does. 774 */ 775 void SetAttribute( const char * name, int value ); 776 777 /** Deletes an attribute with the given name. 778 */ 779 void RemoveAttribute( const char * name ); 780 #ifdef TIXML_USE_STL RemoveAttribute(const std::string & name)781 void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. 782 #endif 783 FirstAttribute()784 TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. LastAttribute()785 TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. 786 787 // [internal use] Creates a new Element and returs it. 788 virtual TiXmlNode* Clone() const; 789 // [internal use] 790 791 virtual void Print( FILE* cfile, int depth ) const; 792 793 protected: 794 795 // Used to be public [internal use] 796 #ifdef TIXML_USE_STL 797 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 798 #endif 799 virtual void StreamOut( TIXML_OSTREAM * out ) const; 800 801 /* [internal use] 802 Attribtue parsing starts: next char past '<' 803 returns: next char past '>' 804 */ 805 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 806 807 /* [internal use] 808 Reads the "value" of the element -- another element, or text. 809 This should terminate with the current end tag. 810 */ 811 const char* ReadValue( const char* in, TiXmlParsingData* prevData ); 812 813 private: 814 TiXmlAttributeSet attributeSet; 815 }; 816 817 818 /** An XML comment. 819 */ 820 class CAL3D_API TiXmlComment : public TiXmlNode 821 { 822 public: 823 /// Constructs an empty comment. TiXmlComment()824 TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} ~TiXmlComment()825 virtual ~TiXmlComment() {} 826 827 // [internal use] Creates a new Element and returs it. 828 virtual TiXmlNode* Clone() const; 829 // [internal use] 830 virtual void Print( FILE* cfile, int depth ) const; 831 protected: 832 // used to be public 833 #ifdef TIXML_USE_STL 834 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 835 #endif 836 virtual void StreamOut( TIXML_OSTREAM * out ) const; 837 /* [internal use] 838 Attribtue parsing starts: at the ! of the !-- 839 returns: next char past '>' 840 */ 841 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 842 }; 843 844 845 /** XML text. Contained in an element. 846 */ 847 class CAL3D_API TiXmlText : public TiXmlNode 848 { 849 friend class TiXmlElement; 850 public: 851 /// Constructor. TiXmlText(const char * initValue)852 TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) 853 { 854 SetValue( initValue ); 855 } ~TiXmlText()856 virtual ~TiXmlText() {} 857 858 #ifdef TIXML_USE_STL 859 /// Constructor. TiXmlText(const std::string & initValue)860 TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) 861 { 862 SetValue( initValue ); 863 } 864 #endif 865 866 // [internal use] 867 virtual void Print( FILE* cfile, int depth ) const; 868 869 protected : 870 // [internal use] Creates a new Element and returns it. 871 virtual TiXmlNode* Clone() const; 872 virtual void StreamOut ( TIXML_OSTREAM * out ) const; 873 // [internal use] 874 bool Blank() const; // returns true if all white space and new lines 875 /* [internal use] 876 Attribtue parsing starts: First char of the text 877 returns: next char past '>' 878 */ 879 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 880 // [internal use] 881 #ifdef TIXML_USE_STL 882 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 883 #endif 884 }; 885 886 887 /** In correct XML the declaration is the first entry in the file. 888 @verbatim 889 <?xml version="1.0" standalone="yes"?> 890 @endverbatim 891 892 TinyXml will happily read or write files without a declaration, 893 however. There are 3 possible attributes to the declaration: 894 version, encoding, and standalone. 895 896 Note: In this version of the code, the attributes are 897 handled as special cases, not generic attributes, simply 898 because there can only be at most 3 and they are always the same. 899 */ 900 class CAL3D_API TiXmlDeclaration : public TiXmlNode 901 { 902 public: 903 /// Construct an empty declaration. TiXmlDeclaration()904 TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} 905 906 #ifdef TIXML_USE_STL 907 /// Constructor. TiXmlDeclaration(const std::string & _version,const std::string & _encoding,const std::string & _standalone)908 TiXmlDeclaration( const std::string& _version, 909 const std::string& _encoding, 910 const std::string& _standalone ) 911 : TiXmlNode( TiXmlNode::DECLARATION ) 912 { 913 version = _version; 914 encoding = _encoding; 915 standalone = _standalone; 916 } 917 #endif 918 919 /// Construct. 920 TiXmlDeclaration( const char* _version, 921 const char* _encoding, 922 const char* _standalone ); 923 ~TiXmlDeclaration()924 virtual ~TiXmlDeclaration() {} 925 926 /// Version. Will return empty if none was found. Version()927 const char * Version() const { return version.c_str (); } 928 /// Encoding. Will return empty if none was found. Encoding()929 const char * Encoding() const { return encoding.c_str (); } 930 /// Is this a standalone document? Standalone()931 const char * Standalone() const { return standalone.c_str (); } 932 933 // [internal use] Creates a new Element and returs it. 934 virtual TiXmlNode* Clone() const; 935 // [internal use] 936 virtual void Print( FILE* cfile, int depth ) const; 937 938 protected: 939 // used to be public 940 #ifdef TIXML_USE_STL 941 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 942 #endif 943 virtual void StreamOut ( TIXML_OSTREAM * out) const; 944 // [internal use] 945 // Attribtue parsing starts: next char past '<' 946 // returns: next char past '>' 947 948 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 949 950 private: 951 TIXML_STRING version; 952 TIXML_STRING encoding; 953 TIXML_STRING standalone; 954 }; 955 956 957 /** Any tag that tinyXml doesn't recognize is saved as an 958 unknown. It is a tag of text, but should not be modified. 959 It will be written back to the XML, unchanged, when the file 960 is saved. 961 */ 962 class CAL3D_API TiXmlUnknown : public TiXmlNode 963 { 964 public: TiXmlUnknown()965 TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} ~TiXmlUnknown()966 virtual ~TiXmlUnknown() {} 967 968 // [internal use] 969 virtual TiXmlNode* Clone() const; 970 // [internal use] 971 virtual void Print( FILE* cfile, int depth ) const; 972 protected: 973 #ifdef TIXML_USE_STL 974 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 975 #endif 976 virtual void StreamOut ( TIXML_OSTREAM * out ) const; 977 /* [internal use] 978 Attribute parsing starts: First char of the text 979 returns: next char past '>' 980 */ 981 virtual const char* Parse( const char* p, TiXmlParsingData* data ); 982 }; 983 984 985 /** Always the top level node. A document binds together all the 986 XML pieces. It can be saved, loaded, and printed to the screen. 987 The 'value' of a document node is the xml file name. 988 */ 989 class CAL3D_API TiXmlDocument : public TiXmlNode 990 { 991 public: 992 /// Create an empty document, that has no name. 993 TiXmlDocument(); 994 /// Create a document with a name. The name of the document is also the filename of the xml. 995 TiXmlDocument( const char * documentName ); 996 997 #ifdef TIXML_USE_STL 998 /// Constructor. TiXmlDocument(const std::string & documentName)999 TiXmlDocument( const std::string& documentName ) : 1000 TiXmlNode( TiXmlNode::DOCUMENT ) 1001 { 1002 tabsize = 4; 1003 value = documentName; 1004 error = false; 1005 } 1006 #endif 1007 ~TiXmlDocument()1008 virtual ~TiXmlDocument() {} 1009 1010 /** Load a file using the current document value. 1011 Returns true if successful. Will delete any existing 1012 document data before loading. 1013 */ 1014 bool LoadFile(); 1015 /// Save a file using the current document value. Returns true if successful. 1016 bool SaveFile() const; 1017 /// Load a file using the given filename. Returns true if successful. 1018 bool LoadFile( const char * filename ); 1019 /// Save a file using the given filename. Returns true if successful. 1020 bool SaveFile( const char * filename ) const; 1021 1022 #ifdef TIXML_USE_STL LoadFile(const std::string & filename)1023 bool LoadFile( const std::string& filename ) ///< STL std::string version. 1024 { 1025 StringToBuffer f( filename ); 1026 return ( f.buffer && LoadFile( f.buffer )); 1027 } SaveFile(const std::string & filename)1028 bool SaveFile( const std::string& filename ) const ///< STL std::string version. 1029 { 1030 StringToBuffer f( filename ); 1031 return ( f.buffer && SaveFile( f.buffer )); 1032 } 1033 #endif 1034 1035 /** Parse the given null terminated block of xml data. 1036 */ 1037 virtual const char* Parse( const char* p, TiXmlParsingData* data = 0 ); 1038 1039 /** Get the root element -- the only top level element -- of the document. 1040 In well formed XML, there should only be one. TinyXml is tolerant of 1041 multiple elements at the document level. 1042 */ RootElement()1043 TiXmlElement* RootElement() const { return FirstChildElement(); } 1044 1045 /** If an error occurs, Error will be set to true. Also, 1046 - The ErrorId() will contain the integer identifier of the error (not generally useful) 1047 - The ErrorDesc() method will return the name of the error. (very useful) 1048 - The ErrorRow() and ErrorCol() will return the location of the error (if known) 1049 */ Error()1050 bool Error() const { return error; } 1051 1052 /// Contains a textual (english) description of the error if one occurs. ErrorDesc()1053 const char * ErrorDesc() const { return errorDesc.c_str (); } 1054 1055 /** Generally, you probably want the error string ( ErrorDesc() ). But if you 1056 prefer the ErrorId, this function will fetch it. 1057 */ ErrorId()1058 const int ErrorId() const { return errorId; } 1059 1060 /** Returns the location (if known) of the error. The first column is column 1, 1061 and the first row is row 1. A value of 0 means the row and column wasn't applicable 1062 (memory errors, for example, have no row/column) or the parser lost the error. (An 1063 error in the error reporting, in that case.) 1064 1065 @sa SetTabSize, Row, Column 1066 */ ErrorRow()1067 int ErrorRow() { return errorLocation.row+1; } ErrorCol()1068 int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() 1069 1070 /** By calling this method, with a tab size 1071 greater than 0, the row and column of each node and attribute is stored 1072 when the file is loaded. Very useful for tracking the DOM back in to 1073 the source file. 1074 1075 The tab size is required for calculating the location of nodes. If not 1076 set, the default of 4 is used. The tabsize is set per document. Setting 1077 the tabsize to 0 disables row/column tracking. 1078 1079 Note that row and column tracking is not supported when using operator>>. 1080 1081 The tab size needs to be enabled before the parse or load. Correct usage: 1082 @verbatim 1083 TiXmlDocument doc; 1084 doc.SetTabSize( 8 ); 1085 doc.Load( "myfile.xml" ); 1086 @endverbatim 1087 1088 @sa Row, Column 1089 */ SetTabSize(int _tabsize)1090 void SetTabSize( int _tabsize ) { tabsize = _tabsize; } 1091 TabSize()1092 int TabSize() const { return tabsize; } 1093 1094 /** If you have handled the error, it can be reset with this call. The error 1095 state is automatically cleared if you Parse a new XML block. 1096 */ ClearError()1097 void ClearError() { error = false; 1098 errorId = 0; 1099 errorDesc = ""; 1100 errorLocation.row = errorLocation.col = 0; 1101 //errorLocation.last = 0; 1102 } 1103 1104 /** Dump the document to standard out. */ Print()1105 void Print() const { Print( stdout, 0 ); } 1106 1107 // [internal use] 1108 virtual void Print( FILE* cfile, int depth = 0 ) const; 1109 // [internal use] 1110 void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData ); 1111 1112 protected : 1113 virtual void StreamOut ( TIXML_OSTREAM * out) const; 1114 // [internal use] 1115 virtual TiXmlNode* Clone() const; 1116 #ifdef TIXML_USE_STL 1117 virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); 1118 #endif 1119 1120 private: 1121 bool error; 1122 int errorId; 1123 TIXML_STRING errorDesc; 1124 int tabsize; 1125 TiXmlCursor errorLocation; 1126 }; 1127 1128 1129 /** 1130 A TiXmlHandle is a class that wraps a node pointer with null checks; this is 1131 an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml 1132 DOM structure. It is a separate utility class. 1133 1134 Take an example: 1135 @verbatim 1136 <Document> 1137 <Element attributeA = "valueA"> 1138 <Child attributeB = "value1" /> 1139 <Child attributeB = "value2" /> 1140 </Element> 1141 <Document> 1142 @endverbatim 1143 1144 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 1145 easy to write a *lot* of code that looks like: 1146 1147 @verbatim 1148 TiXmlElement* root = document.FirstChildElement( "Document" ); 1149 if ( root ) 1150 { 1151 TiXmlElement* element = root->FirstChildElement( "Element" ); 1152 if ( element ) 1153 { 1154 TiXmlElement* child = element->FirstChildElement( "Child" ); 1155 if ( child ) 1156 { 1157 TiXmlElement* child2 = child->NextSiblingElement( "Child" ); 1158 if ( child2 ) 1159 { 1160 // Finally do something useful. 1161 @endverbatim 1162 1163 And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity 1164 of such code. A TiXmlHandle checks for null pointers so it is perfectly safe 1165 and correct to use: 1166 1167 @verbatim 1168 TiXmlHandle docHandle( &document ); 1169 TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); 1170 if ( child2 ) 1171 { 1172 // do something useful 1173 @endverbatim 1174 1175 Which is MUCH more concise and useful. 1176 1177 It is also safe to copy handles - internally they are nothing more than node pointers. 1178 @verbatim 1179 TiXmlHandle handleCopy = handle; 1180 @endverbatim 1181 1182 What they should not be used for is iteration: 1183 1184 @verbatim 1185 int i=0; 1186 while ( true ) 1187 { 1188 TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); 1189 if ( !child ) 1190 break; 1191 // do something 1192 ++i; 1193 } 1194 @endverbatim 1195 1196 It seems reasonable, but it is in fact two embedded while loops. The Child method is 1197 a linear walk to find the element, so this code would iterate much more than it needs 1198 to. Instead, prefer: 1199 1200 @verbatim 1201 TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); 1202 1203 for( child; child; child=child->NextSiblingElement() ) 1204 { 1205 // do something 1206 } 1207 @endverbatim 1208 */ 1209 class CAL3D_API TiXmlHandle 1210 { 1211 public: 1212 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. TiXmlHandle(TiXmlNode * node)1213 TiXmlHandle( TiXmlNode* node ) { this->node = node; } 1214 /// Copy constructor TiXmlHandle(const TiXmlHandle & ref)1215 TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } 1216 1217 /// Return a handle to the first child node. 1218 TiXmlHandle FirstChild() const; 1219 /// Return a handle to the first child node with the given name. 1220 TiXmlHandle FirstChild( const char * value ) const; 1221 /// Return a handle to the first child element. 1222 TiXmlHandle FirstChildElement() const; 1223 /// Return a handle to the first child element with the given name. 1224 TiXmlHandle FirstChildElement( const char * value ) const; 1225 1226 /** Return a handle to the "index" child with the given name. 1227 The first child is 0, the second 1, etc. 1228 */ 1229 TiXmlHandle Child( const char* value, int index ) const; 1230 /** Return a handle to the "index" child. 1231 The first child is 0, the second 1, etc. 1232 */ 1233 TiXmlHandle Child( int index ) const; 1234 /** Return a handle to the "index" child element with the given name. 1235 The first child element is 0, the second 1, etc. Note that only TiXmlElements 1236 are indexed: other types are not counted. 1237 */ 1238 TiXmlHandle ChildElement( const char* value, int index ) const; 1239 /** Return a handle to the "index" child element. 1240 The first child element is 0, the second 1, etc. Note that only TiXmlElements 1241 are indexed: other types are not counted. 1242 */ 1243 TiXmlHandle ChildElement( int index ) const; 1244 1245 #ifdef TIXML_USE_STL FirstChild(const std::string & _value)1246 TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } FirstChildElement(const std::string & _value)1247 TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } 1248 Child(const std::string & _value,int index)1249 TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } ChildElement(const std::string & _value,int index)1250 TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } 1251 #endif 1252 1253 /// Return the handle as a TiXmlNode. This may return null. Node()1254 TiXmlNode* Node() const { return node; } 1255 /// Return the handle as a TiXmlElement. This may return null. Element()1256 TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } 1257 /// Return the handle as a TiXmlText. This may return null. Text()1258 TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } 1259 1260 private: 1261 TiXmlNode* node; 1262 }; 1263 1264 } 1265 1266 #endif 1267 1268