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 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28 # include <ctype.h>
29 # include <limits.h>
30 # include <stdio.h>
31 # include <stdlib.h>
32 # include <string.h>
33 # if defined(__PS3__)
34 # include <stddef.h>
35 # endif
36 #else
37 # include <cctype>
38 # include <climits>
39 # include <cstdio>
40 # include <cstdlib>
41 # include <cstring>
42 #endif
43 #include <stdint.h>
44
45 /*
46 TODO: intern strings instead of allocation.
47 */
48 /*
49 gcc:
50 g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
51
52 Formatting, Artistic Style:
53 AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
54 */
55
56 #if defined( _DEBUG ) || defined (__DEBUG__)
57 # ifndef TINYXML2_DEBUG
58 # define TINYXML2_DEBUG
59 # endif
60 #endif
61
62 #ifdef _MSC_VER
63 # pragma warning(push)
64 # pragma warning(disable: 4251)
65 #endif
66
67 #ifdef _WIN32
68 # ifdef TINYXML2_EXPORT
69 # define TINYXML2_LIB __declspec(dllexport)
70 # elif defined(TINYXML2_IMPORT)
71 # define TINYXML2_LIB __declspec(dllimport)
72 # else
73 # define TINYXML2_LIB
74 # endif
75 #elif __GNUC__ >= 4
76 # define TINYXML2_LIB __attribute__((visibility("default")))
77 #else
78 # define TINYXML2_LIB
79 #endif
80
81
82 #if defined(TINYXML2_DEBUG)
83 # if defined(_MSC_VER)
84 # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
85 # define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
86 # elif defined (ANDROID_NDK)
87 # include <android/log.h>
88 # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
89 # else
90 # include <assert.h>
91 # define TIXMLASSERT assert
92 # endif
93 #else
94 # define TIXMLASSERT( x ) {}
95 #endif
96
97
98 /* Versioning, past 1.0.14:
99 http://semver.org/
100 */
101 static const int TIXML2_MAJOR_VERSION = 8;
102 static const int TIXML2_MINOR_VERSION = 0;
103 static const int TIXML2_PATCH_VERSION = 0;
104
105 #define TINYXML2_MAJOR_VERSION 8
106 #define TINYXML2_MINOR_VERSION 0
107 #define TINYXML2_PATCH_VERSION 0
108
109 // A fixed element depth limit is problematic. There needs to be a
110 // limit to avoid a stack overflow. However, that limit varies per
111 // system, and the capacity of the stack. On the other hand, it's a trivial
112 // attack that can result from ill, malicious, or even correctly formed XML,
113 // so there needs to be a limit in place.
114 static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
115
116 namespace tinyxml2
117 {
118 class XMLDocument;
119 class XMLElement;
120 class XMLAttribute;
121 class XMLComment;
122 class XMLText;
123 class XMLDeclaration;
124 class XMLUnknown;
125 class XMLPrinter;
126
127 /*
128 A class that wraps strings. Normally stores the start and end
129 pointers into the XML file itself, and will apply normalization
130 and entity translation if actually read. Can also store (and memory
131 manage) a traditional char[]
132
133 Isn't clear why TINYXML2_LIB is needed; but seems to fix #719
134 */
135 class TINYXML2_LIB StrPair
136 {
137 public:
138 enum {
139 NEEDS_ENTITY_PROCESSING = 0x01,
140 NEEDS_NEWLINE_NORMALIZATION = 0x02,
141 NEEDS_WHITESPACE_COLLAPSING = 0x04,
142
143 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
144 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
145 ATTRIBUTE_NAME = 0,
146 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
147 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
148 COMMENT = NEEDS_NEWLINE_NORMALIZATION
149 };
150
StrPair()151 StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
152 ~StrPair();
153
Set(char * start,char * end,int flags)154 void Set( char* start, char* end, int flags ) {
155 TIXMLASSERT( start );
156 TIXMLASSERT( end );
157 Reset();
158 _start = start;
159 _end = end;
160 _flags = flags | NEEDS_FLUSH;
161 }
162
163 const char* GetStr();
164
Empty()165 bool Empty() const {
166 return _start == _end;
167 }
168
SetInternedStr(const char * str)169 void SetInternedStr( const char* str ) {
170 Reset();
171 _start = const_cast<char*>(str);
172 }
173
174 void SetStr( const char* str, int flags=0 );
175
176 char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
177 char* ParseName( char* in );
178
179 void TransferTo( StrPair* other );
180 void Reset();
181
182 private:
183 void CollapseWhitespace();
184
185 enum {
186 NEEDS_FLUSH = 0x100,
187 NEEDS_DELETE = 0x200
188 };
189
190 int _flags;
191 char* _start;
192 char* _end;
193
194 StrPair( const StrPair& other ); // not supported
195 void operator=( const StrPair& other ); // not supported, use TransferTo()
196 };
197
198
199 /*
200 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
201 Has a small initial memory pool, so that low or no usage will not
202 cause a call to new/delete
203 */
204 template <class T, int INITIAL_SIZE>
205 class DynArray
206 {
207 public:
DynArray()208 DynArray() :
209 _mem( _pool ),
210 _allocated( INITIAL_SIZE ),
211 _size( 0 )
212 {
213 }
214
~DynArray()215 ~DynArray() {
216 if ( _mem != _pool ) {
217 delete [] _mem;
218 }
219 }
220
Clear()221 void Clear() {
222 _size = 0;
223 }
224
Push(T t)225 void Push( T t ) {
226 TIXMLASSERT( _size < INT_MAX );
227 EnsureCapacity( _size+1 );
228 _mem[_size] = t;
229 ++_size;
230 }
231
PushArr(int count)232 T* PushArr( int count ) {
233 TIXMLASSERT( count >= 0 );
234 TIXMLASSERT( _size <= INT_MAX - count );
235 EnsureCapacity( _size+count );
236 T* ret = &_mem[_size];
237 _size += count;
238 return ret;
239 }
240
Pop()241 T Pop() {
242 TIXMLASSERT( _size > 0 );
243 --_size;
244 return _mem[_size];
245 }
246
PopArr(int count)247 void PopArr( int count ) {
248 TIXMLASSERT( _size >= count );
249 _size -= count;
250 }
251
Empty()252 bool Empty() const {
253 return _size == 0;
254 }
255
256 T& operator[](int i) {
257 TIXMLASSERT( i>= 0 && i < _size );
258 return _mem[i];
259 }
260
261 const T& operator[](int i) const {
262 TIXMLASSERT( i>= 0 && i < _size );
263 return _mem[i];
264 }
265
PeekTop()266 const T& PeekTop() const {
267 TIXMLASSERT( _size > 0 );
268 return _mem[ _size - 1];
269 }
270
Size()271 int Size() const {
272 TIXMLASSERT( _size >= 0 );
273 return _size;
274 }
275
Capacity()276 int Capacity() const {
277 TIXMLASSERT( _allocated >= INITIAL_SIZE );
278 return _allocated;
279 }
280
SwapRemove(int i)281 void SwapRemove(int i) {
282 TIXMLASSERT(i >= 0 && i < _size);
283 TIXMLASSERT(_size > 0);
284 _mem[i] = _mem[_size - 1];
285 --_size;
286 }
287
Mem()288 const T* Mem() const {
289 TIXMLASSERT( _mem );
290 return _mem;
291 }
292
Mem()293 T* Mem() {
294 TIXMLASSERT( _mem );
295 return _mem;
296 }
297
298 private:
299 DynArray( const DynArray& ); // not supported
300 void operator=( const DynArray& ); // not supported
301
EnsureCapacity(int cap)302 void EnsureCapacity( int cap ) {
303 TIXMLASSERT( cap > 0 );
304 if ( cap > _allocated ) {
305 TIXMLASSERT( cap <= INT_MAX / 2 );
306 const int newAllocated = cap * 2;
307 T* newMem = new T[newAllocated];
308 TIXMLASSERT( newAllocated >= _size );
309 memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
310 if ( _mem != _pool ) {
311 delete [] _mem;
312 }
313 _mem = newMem;
314 _allocated = newAllocated;
315 }
316 }
317
318 T* _mem;
319 T _pool[INITIAL_SIZE];
320 int _allocated; // objects allocated
321 int _size; // number objects in use
322 };
323
324
325 /*
326 Parent virtual class of a pool for fast allocation
327 and deallocation of objects.
328 */
329 class MemPool
330 {
331 public:
MemPool()332 MemPool() {}
~MemPool()333 virtual ~MemPool() {}
334
335 virtual int ItemSize() const = 0;
336 virtual void* Alloc() = 0;
337 virtual void Free( void* ) = 0;
338 virtual void SetTracked() = 0;
339 };
340
341
342 /*
343 Template child class to create pools of the correct type.
344 */
345 template< int ITEM_SIZE >
346 class MemPoolT : public MemPool
347 {
348 public:
MemPoolT()349 MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
~MemPoolT()350 ~MemPoolT() {
351 MemPoolT< ITEM_SIZE >::Clear();
352 }
353
Clear()354 void Clear() {
355 // Delete the blocks.
356 while( !_blockPtrs.Empty()) {
357 Block* lastBlock = _blockPtrs.Pop();
358 delete lastBlock;
359 }
360 _root = 0;
361 _currentAllocs = 0;
362 _nAllocs = 0;
363 _maxAllocs = 0;
364 _nUntracked = 0;
365 }
366
ItemSize()367 virtual int ItemSize() const {
368 return ITEM_SIZE;
369 }
CurrentAllocs()370 int CurrentAllocs() const {
371 return _currentAllocs;
372 }
373
Alloc()374 virtual void* Alloc() {
375 if ( !_root ) {
376 // Need a new block.
377 Block* block = new Block();
378 _blockPtrs.Push( block );
379
380 Item* blockItems = block->items;
381 for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
382 blockItems[i].next = &(blockItems[i + 1]);
383 }
384 blockItems[ITEMS_PER_BLOCK - 1].next = 0;
385 _root = blockItems;
386 }
387 Item* const result = _root;
388 TIXMLASSERT( result != 0 );
389 _root = _root->next;
390
391 ++_currentAllocs;
392 if ( _currentAllocs > _maxAllocs ) {
393 _maxAllocs = _currentAllocs;
394 }
395 ++_nAllocs;
396 ++_nUntracked;
397 return result;
398 }
399
Free(void * mem)400 virtual void Free( void* mem ) {
401 if ( !mem ) {
402 return;
403 }
404 --_currentAllocs;
405 Item* item = static_cast<Item*>( mem );
406 #ifdef TINYXML2_DEBUG
407 memset( item, 0xfe, sizeof( *item ) );
408 #endif
409 item->next = _root;
410 _root = item;
411 }
Trace(const char * name)412 void Trace( const char* name ) {
413 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
414 name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
415 ITEM_SIZE, _nAllocs, _blockPtrs.Size() );
416 }
417
SetTracked()418 void SetTracked() {
419 --_nUntracked;
420 }
421
Untracked()422 int Untracked() const {
423 return _nUntracked;
424 }
425
426 // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
427 // The test file is large, 170k.
428 // Release: VS2010 gcc(no opt)
429 // 1k: 4000
430 // 2k: 4000
431 // 4k: 3900 21000
432 // 16k: 5200
433 // 32k: 4300
434 // 64k: 4000 21000
435 // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
436 // in private part if ITEMS_PER_BLOCK is private
437 enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
438
439 private:
440 MemPoolT( const MemPoolT& ); // not supported
441 void operator=( const MemPoolT& ); // not supported
442
443 union Item {
444 Item* next;
445 char itemData[ITEM_SIZE];
446 };
447 struct Block {
448 Item items[ITEMS_PER_BLOCK];
449 };
450 DynArray< Block*, 10 > _blockPtrs;
451 Item* _root;
452
453 int _currentAllocs;
454 int _nAllocs;
455 int _maxAllocs;
456 int _nUntracked;
457 };
458
459
460
461 /**
462 Implements the interface to the "Visitor pattern" (see the Accept() method.)
463 If you call the Accept() method, it requires being passed a XMLVisitor
464 class to handle callbacks. For nodes that contain other nodes (Document, Element)
465 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
466 are simply called with Visit().
467
468 If you return 'true' from a Visit method, recursive parsing will continue. If you return
469 false, <b>no children of this node or its siblings</b> will be visited.
470
471 All flavors of Visit methods have a default implementation that returns 'true' (continue
472 visiting). You need to only override methods that are interesting to you.
473
474 Generally Accept() is called on the XMLDocument, although all nodes support visiting.
475
476 You should never change the document from a callback.
477
478 @sa XMLNode::Accept()
479 */
480 class TINYXML2_LIB XMLVisitor
481 {
482 public:
~XMLVisitor()483 virtual ~XMLVisitor() {}
484
485 /// Visit a document.
VisitEnter(const XMLDocument &)486 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
487 return true;
488 }
489 /// Visit a document.
VisitExit(const XMLDocument &)490 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
491 return true;
492 }
493
494 /// Visit an element.
VisitEnter(const XMLElement &,const XMLAttribute *)495 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
496 return true;
497 }
498 /// Visit an element.
VisitExit(const XMLElement &)499 virtual bool VisitExit( const XMLElement& /*element*/ ) {
500 return true;
501 }
502
503 /// Visit a declaration.
Visit(const XMLDeclaration &)504 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
505 return true;
506 }
507 /// Visit a text node.
Visit(const XMLText &)508 virtual bool Visit( const XMLText& /*text*/ ) {
509 return true;
510 }
511 /// Visit a comment node.
Visit(const XMLComment &)512 virtual bool Visit( const XMLComment& /*comment*/ ) {
513 return true;
514 }
515 /// Visit an unknown node.
Visit(const XMLUnknown &)516 virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
517 return true;
518 }
519 };
520
521 // WARNING: must match XMLDocument::_errorNames[]
522 enum XMLError {
523 XML_SUCCESS = 0,
524 XML_NO_ATTRIBUTE,
525 XML_WRONG_ATTRIBUTE_TYPE,
526 XML_ERROR_FILE_NOT_FOUND,
527 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
528 XML_ERROR_FILE_READ_ERROR,
529 XML_ERROR_PARSING_ELEMENT,
530 XML_ERROR_PARSING_ATTRIBUTE,
531 XML_ERROR_PARSING_TEXT,
532 XML_ERROR_PARSING_CDATA,
533 XML_ERROR_PARSING_COMMENT,
534 XML_ERROR_PARSING_DECLARATION,
535 XML_ERROR_PARSING_UNKNOWN,
536 XML_ERROR_EMPTY_DOCUMENT,
537 XML_ERROR_MISMATCHED_ELEMENT,
538 XML_ERROR_PARSING,
539 XML_CAN_NOT_CONVERT_TEXT,
540 XML_NO_TEXT_NODE,
541 XML_ELEMENT_DEPTH_EXCEEDED,
542
543 XML_ERROR_COUNT
544 };
545
546
547 /*
548 Utility functionality.
549 */
550 class TINYXML2_LIB XMLUtil
551 {
552 public:
SkipWhiteSpace(const char * p,int * curLineNumPtr)553 static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
554 TIXMLASSERT( p );
555
556 while( IsWhiteSpace(*p) ) {
557 if (curLineNumPtr && *p == '\n') {
558 ++(*curLineNumPtr);
559 }
560 ++p;
561 }
562 TIXMLASSERT( p );
563 return p;
564 }
SkipWhiteSpace(char * const p,int * curLineNumPtr)565 static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) {
566 return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
567 }
568
569 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
570 // correct, but simple, and usually works.
IsWhiteSpace(char p)571 static bool IsWhiteSpace( char p ) {
572 return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
573 }
574
IsNameStartChar(unsigned char ch)575 inline static bool IsNameStartChar( unsigned char ch ) {
576 if ( ch >= 128 ) {
577 // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
578 return true;
579 }
580 if ( isalpha( ch ) ) {
581 return true;
582 }
583 return ch == ':' || ch == '_';
584 }
585
IsNameChar(unsigned char ch)586 inline static bool IsNameChar( unsigned char ch ) {
587 return IsNameStartChar( ch )
588 || isdigit( ch )
589 || ch == '.'
590 || ch == '-';
591 }
592
IsPrefixHex(const char * p)593 inline static bool IsPrefixHex( const char* p) {
594 p = SkipWhiteSpace(p, 0);
595 return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X');
596 }
597
598 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
599 if ( p == q ) {
600 return true;
601 }
602 TIXMLASSERT( p );
603 TIXMLASSERT( q );
604 TIXMLASSERT( nChar >= 0 );
605 return strncmp( p, q, nChar ) == 0;
606 }
607
IsUTF8Continuation(const char p)608 inline static bool IsUTF8Continuation( const char p ) {
609 return ( p & 0x80 ) != 0;
610 }
611
612 static const char* ReadBOM( const char* p, bool* hasBOM );
613 // p is the starting location,
614 // the UTF-8 value of the entity will be placed in value, and length filled in.
615 static const char* GetCharacterRef( const char* p, char* value, int* length );
616 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
617
618 // converts primitive types to strings
619 static void ToStr( int v, char* buffer, int bufferSize );
620 static void ToStr( unsigned v, char* buffer, int bufferSize );
621 static void ToStr( bool v, char* buffer, int bufferSize );
622 static void ToStr( float v, char* buffer, int bufferSize );
623 static void ToStr( double v, char* buffer, int bufferSize );
624 static void ToStr(int64_t v, char* buffer, int bufferSize);
625 static void ToStr(uint64_t v, char* buffer, int bufferSize);
626
627 // converts strings to primitive types
628 static bool ToInt( const char* str, int* value );
629 static bool ToUnsigned( const char* str, unsigned* value );
630 static bool ToBool( const char* str, bool* value );
631 static bool ToFloat( const char* str, float* value );
632 static bool ToDouble( const char* str, double* value );
633 static bool ToInt64(const char* str, int64_t* value);
634 static bool ToUnsigned64(const char* str, uint64_t* value);
635 // Changes what is serialized for a boolean value.
636 // Default to "true" and "false". Shouldn't be changed
637 // unless you have a special testing or compatibility need.
638 // Be careful: static, global, & not thread safe.
639 // Be sure to set static const memory as parameters.
640 static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
641
642 private:
643 static const char* writeBoolTrue;
644 static const char* writeBoolFalse;
645 };
646
647
648 /** XMLNode is a base class for every object that is in the
649 XML Document Object Model (DOM), except XMLAttributes.
650 Nodes have siblings, a parent, and children which can
651 be navigated. A node is always in a XMLDocument.
652 The type of a XMLNode can be queried, and it can
653 be cast to its more defined type.
654
655 A XMLDocument allocates memory for all its Nodes.
656 When the XMLDocument gets deleted, all its Nodes
657 will also be deleted.
658
659 @verbatim
660 A Document can contain: Element (container or leaf)
661 Comment (leaf)
662 Unknown (leaf)
663 Declaration( leaf )
664
665 An Element can contain: Element (container or leaf)
666 Text (leaf)
667 Attributes (not on tree)
668 Comment (leaf)
669 Unknown (leaf)
670
671 @endverbatim
672 */
673 class TINYXML2_LIB XMLNode
674 {
675 friend class XMLDocument;
676 friend class XMLElement;
677 public:
678
679 /// Get the XMLDocument that owns this XMLNode.
GetDocument()680 const XMLDocument* GetDocument() const {
681 TIXMLASSERT( _document );
682 return _document;
683 }
684 /// Get the XMLDocument that owns this XMLNode.
GetDocument()685 XMLDocument* GetDocument() {
686 TIXMLASSERT( _document );
687 return _document;
688 }
689
690 /// Safely cast to an Element, or null.
ToElement()691 virtual XMLElement* ToElement() {
692 return 0;
693 }
694 /// Safely cast to Text, or null.
ToText()695 virtual XMLText* ToText() {
696 return 0;
697 }
698 /// Safely cast to a Comment, or null.
ToComment()699 virtual XMLComment* ToComment() {
700 return 0;
701 }
702 /// Safely cast to a Document, or null.
ToDocument()703 virtual XMLDocument* ToDocument() {
704 return 0;
705 }
706 /// Safely cast to a Declaration, or null.
ToDeclaration()707 virtual XMLDeclaration* ToDeclaration() {
708 return 0;
709 }
710 /// Safely cast to an Unknown, or null.
ToUnknown()711 virtual XMLUnknown* ToUnknown() {
712 return 0;
713 }
714
ToElement()715 virtual const XMLElement* ToElement() const {
716 return 0;
717 }
ToText()718 virtual const XMLText* ToText() const {
719 return 0;
720 }
ToComment()721 virtual const XMLComment* ToComment() const {
722 return 0;
723 }
ToDocument()724 virtual const XMLDocument* ToDocument() const {
725 return 0;
726 }
ToDeclaration()727 virtual const XMLDeclaration* ToDeclaration() const {
728 return 0;
729 }
ToUnknown()730 virtual const XMLUnknown* ToUnknown() const {
731 return 0;
732 }
733
734 /** The meaning of 'value' changes for the specific type.
735 @verbatim
736 Document: empty (NULL is returned, not an empty string)
737 Element: name of the element
738 Comment: the comment text
739 Unknown: the tag contents
740 Text: the text string
741 @endverbatim
742 */
743 const char* Value() const;
744
745 /** Set the Value of an XML node.
746 @sa Value()
747 */
748 void SetValue( const char* val, bool staticMem=false );
749
750 /// Gets the line number the node is in, if the document was parsed from a file.
GetLineNum()751 int GetLineNum() const { return _parseLineNum; }
752
753 /// Get the parent of this node on the DOM.
Parent()754 const XMLNode* Parent() const {
755 return _parent;
756 }
757
Parent()758 XMLNode* Parent() {
759 return _parent;
760 }
761
762 /// Returns true if this node has no children.
NoChildren()763 bool NoChildren() const {
764 return !_firstChild;
765 }
766
767 /// Get the first child node, or null if none exists.
FirstChild()768 const XMLNode* FirstChild() const {
769 return _firstChild;
770 }
771
FirstChild()772 XMLNode* FirstChild() {
773 return _firstChild;
774 }
775
776 /** Get the first child element, or optionally the first child
777 element with the specified name.
778 */
779 const XMLElement* FirstChildElement( const char* name = 0 ) const;
780
781 XMLElement* FirstChildElement( const char* name = 0 ) {
782 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
783 }
784
785 /// Get the last child node, or null if none exists.
LastChild()786 const XMLNode* LastChild() const {
787 return _lastChild;
788 }
789
LastChild()790 XMLNode* LastChild() {
791 return _lastChild;
792 }
793
794 /** Get the last child element or optionally the last child
795 element with the specified name.
796 */
797 const XMLElement* LastChildElement( const char* name = 0 ) const;
798
799 XMLElement* LastChildElement( const char* name = 0 ) {
800 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
801 }
802
803 /// Get the previous (left) sibling node of this node.
PreviousSibling()804 const XMLNode* PreviousSibling() const {
805 return _prev;
806 }
807
PreviousSibling()808 XMLNode* PreviousSibling() {
809 return _prev;
810 }
811
812 /// Get the previous (left) sibling element of this node, with an optionally supplied name.
813 const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
814
815 XMLElement* PreviousSiblingElement( const char* name = 0 ) {
816 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
817 }
818
819 /// Get the next (right) sibling node of this node.
NextSibling()820 const XMLNode* NextSibling() const {
821 return _next;
822 }
823
NextSibling()824 XMLNode* NextSibling() {
825 return _next;
826 }
827
828 /// Get the next (right) sibling element of this node, with an optionally supplied name.
829 const XMLElement* NextSiblingElement( const char* name = 0 ) const;
830
831 XMLElement* NextSiblingElement( const char* name = 0 ) {
832 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
833 }
834
835 /**
836 Add a child node as the last (right) child.
837 If the child node is already part of the document,
838 it is moved from its old location to the new location.
839 Returns the addThis argument or 0 if the node does not
840 belong to the same document.
841 */
842 XMLNode* InsertEndChild( XMLNode* addThis );
843
LinkEndChild(XMLNode * addThis)844 XMLNode* LinkEndChild( XMLNode* addThis ) {
845 return InsertEndChild( addThis );
846 }
847 /**
848 Add a child node as the first (left) child.
849 If the child node is already part of the document,
850 it is moved from its old location to the new location.
851 Returns the addThis argument or 0 if the node does not
852 belong to the same document.
853 */
854 XMLNode* InsertFirstChild( XMLNode* addThis );
855 /**
856 Add a node after the specified child node.
857 If the child node is already part of the document,
858 it is moved from its old location to the new location.
859 Returns the addThis argument or 0 if the afterThis node
860 is not a child of this node, or if the node does not
861 belong to the same document.
862 */
863 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
864
865 /**
866 Delete all the children of this node.
867 */
868 void DeleteChildren();
869
870 /**
871 Delete a child of this node.
872 */
873 void DeleteChild( XMLNode* node );
874
875 /**
876 Make a copy of this node, but not its children.
877 You may pass in a Document pointer that will be
878 the owner of the new Node. If the 'document' is
879 null, then the node returned will be allocated
880 from the current Document. (this->GetDocument())
881
882 Note: if called on a XMLDocument, this will return null.
883 */
884 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
885
886 /**
887 Make a copy of this node and all its children.
888
889 If the 'target' is null, then the nodes will
890 be allocated in the current document. If 'target'
891 is specified, the memory will be allocated is the
892 specified XMLDocument.
893
894 NOTE: This is probably not the correct tool to
895 copy a document, since XMLDocuments can have multiple
896 top level XMLNodes. You probably want to use
897 XMLDocument::DeepCopy()
898 */
899 XMLNode* DeepClone( XMLDocument* target ) const;
900
901 /**
902 Test if 2 nodes are the same, but don't test children.
903 The 2 nodes do not need to be in the same Document.
904
905 Note: if called on a XMLDocument, this will return false.
906 */
907 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
908
909 /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
910 XML tree will be conditionally visited and the host will be called back
911 via the XMLVisitor interface.
912
913 This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
914 the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
915 interface versus any other.)
916
917 The interface has been based on ideas from:
918
919 - http://www.saxproject.org/
920 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
921
922 Which are both good references for "visiting".
923
924 An example of using Accept():
925 @verbatim
926 XMLPrinter printer;
927 tinyxmlDoc.Accept( &printer );
928 const char* xmlcstr = printer.CStr();
929 @endverbatim
930 */
931 virtual bool Accept( XMLVisitor* visitor ) const = 0;
932
933 /**
934 Set user data into the XMLNode. TinyXML-2 in
935 no way processes or interprets user data.
936 It is initially 0.
937 */
SetUserData(void * userData)938 void SetUserData(void* userData) { _userData = userData; }
939
940 /**
941 Get user data set into the XMLNode. TinyXML-2 in
942 no way processes or interprets user data.
943 It is initially 0.
944 */
GetUserData()945 void* GetUserData() const { return _userData; }
946
947 protected:
948 explicit XMLNode( XMLDocument* );
949 virtual ~XMLNode();
950
951 virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
952
953 XMLDocument* _document;
954 XMLNode* _parent;
955 mutable StrPair _value;
956 int _parseLineNum;
957
958 XMLNode* _firstChild;
959 XMLNode* _lastChild;
960
961 XMLNode* _prev;
962 XMLNode* _next;
963
964 void* _userData;
965
966 private:
967 MemPool* _memPool;
968 void Unlink( XMLNode* child );
969 static void DeleteNode( XMLNode* node );
970 void InsertChildPreamble( XMLNode* insertThis ) const;
971 const XMLElement* ToElementWithName( const char* name ) const;
972
973 XMLNode( const XMLNode& ); // not supported
974 XMLNode& operator=( const XMLNode& ); // not supported
975 };
976
977
978 /** XML text.
979
980 Note that a text node can have child element nodes, for example:
981 @verbatim
982 <root>This is <b>bold</b></root>
983 @endverbatim
984
985 A text node can have 2 ways to output the next. "normal" output
986 and CDATA. It will default to the mode it was parsed from the XML file and
987 you generally want to leave it alone, but you can change the output mode with
988 SetCData() and query it with CData().
989 */
990 class TINYXML2_LIB XMLText : public XMLNode
991 {
992 friend class XMLDocument;
993 public:
994 virtual bool Accept( XMLVisitor* visitor ) const;
995
ToText()996 virtual XMLText* ToText() {
997 return this;
998 }
ToText()999 virtual const XMLText* ToText() const {
1000 return this;
1001 }
1002
1003 /// Declare whether this should be CDATA or standard text.
SetCData(bool isCData)1004 void SetCData( bool isCData ) {
1005 _isCData = isCData;
1006 }
1007 /// Returns true if this is a CDATA text element.
CData()1008 bool CData() const {
1009 return _isCData;
1010 }
1011
1012 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1013 virtual bool ShallowEqual( const XMLNode* compare ) const;
1014
1015 protected:
XMLText(XMLDocument * doc)1016 explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
~XMLText()1017 virtual ~XMLText() {}
1018
1019 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1020
1021 private:
1022 bool _isCData;
1023
1024 XMLText( const XMLText& ); // not supported
1025 XMLText& operator=( const XMLText& ); // not supported
1026 };
1027
1028
1029 /** An XML Comment. */
1030 class TINYXML2_LIB XMLComment : public XMLNode
1031 {
1032 friend class XMLDocument;
1033 public:
ToComment()1034 virtual XMLComment* ToComment() {
1035 return this;
1036 }
ToComment()1037 virtual const XMLComment* ToComment() const {
1038 return this;
1039 }
1040
1041 virtual bool Accept( XMLVisitor* visitor ) const;
1042
1043 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1044 virtual bool ShallowEqual( const XMLNode* compare ) const;
1045
1046 protected:
1047 explicit XMLComment( XMLDocument* doc );
1048 virtual ~XMLComment();
1049
1050 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
1051
1052 private:
1053 XMLComment( const XMLComment& ); // not supported
1054 XMLComment& operator=( const XMLComment& ); // not supported
1055 };
1056
1057
1058 /** In correct XML the declaration is the first entry in the file.
1059 @verbatim
1060 <?xml version="1.0" standalone="yes"?>
1061 @endverbatim
1062
1063 TinyXML-2 will happily read or write files without a declaration,
1064 however.
1065
1066 The text of the declaration isn't interpreted. It is parsed
1067 and written as a string.
1068 */
1069 class TINYXML2_LIB XMLDeclaration : public XMLNode
1070 {
1071 friend class XMLDocument;
1072 public:
ToDeclaration()1073 virtual XMLDeclaration* ToDeclaration() {
1074 return this;
1075 }
ToDeclaration()1076 virtual const XMLDeclaration* ToDeclaration() const {
1077 return this;
1078 }
1079
1080 virtual bool Accept( XMLVisitor* visitor ) const;
1081
1082 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1083 virtual bool ShallowEqual( const XMLNode* compare ) const;
1084
1085 protected:
1086 explicit XMLDeclaration( XMLDocument* doc );
1087 virtual ~XMLDeclaration();
1088
1089 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1090
1091 private:
1092 XMLDeclaration( const XMLDeclaration& ); // not supported
1093 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
1094 };
1095
1096
1097 /** Any tag that TinyXML-2 doesn't recognize is saved as an
1098 unknown. It is a tag of text, but should not be modified.
1099 It will be written back to the XML, unchanged, when the file
1100 is saved.
1101
1102 DTD tags get thrown into XMLUnknowns.
1103 */
1104 class TINYXML2_LIB XMLUnknown : public XMLNode
1105 {
1106 friend class XMLDocument;
1107 public:
ToUnknown()1108 virtual XMLUnknown* ToUnknown() {
1109 return this;
1110 }
ToUnknown()1111 virtual const XMLUnknown* ToUnknown() const {
1112 return this;
1113 }
1114
1115 virtual bool Accept( XMLVisitor* visitor ) const;
1116
1117 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1118 virtual bool ShallowEqual( const XMLNode* compare ) const;
1119
1120 protected:
1121 explicit XMLUnknown( XMLDocument* doc );
1122 virtual ~XMLUnknown();
1123
1124 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1125
1126 private:
1127 XMLUnknown( const XMLUnknown& ); // not supported
1128 XMLUnknown& operator=( const XMLUnknown& ); // not supported
1129 };
1130
1131
1132
1133 /** An attribute is a name-value pair. Elements have an arbitrary
1134 number of attributes, each with a unique name.
1135
1136 @note The attributes are not XMLNodes. You may only query the
1137 Next() attribute in a list.
1138 */
1139 class TINYXML2_LIB XMLAttribute
1140 {
1141 friend class XMLElement;
1142 public:
1143 /// The name of the attribute.
1144 const char* Name() const;
1145
1146 /// The value of the attribute.
1147 const char* Value() const;
1148
1149 /// Gets the line number the attribute is in, if the document was parsed from a file.
GetLineNum()1150 int GetLineNum() const { return _parseLineNum; }
1151
1152 /// The next attribute in the list.
Next()1153 const XMLAttribute* Next() const {
1154 return _next;
1155 }
1156
1157 /** IntValue interprets the attribute as an integer, and returns the value.
1158 If the value isn't an integer, 0 will be returned. There is no error checking;
1159 use QueryIntValue() if you need error checking.
1160 */
IntValue()1161 int IntValue() const {
1162 int i = 0;
1163 QueryIntValue(&i);
1164 return i;
1165 }
1166
Int64Value()1167 int64_t Int64Value() const {
1168 int64_t i = 0;
1169 QueryInt64Value(&i);
1170 return i;
1171 }
1172
Unsigned64Value()1173 uint64_t Unsigned64Value() const {
1174 uint64_t i = 0;
1175 QueryUnsigned64Value(&i);
1176 return i;
1177 }
1178
1179 /// Query as an unsigned integer. See IntValue()
UnsignedValue()1180 unsigned UnsignedValue() const {
1181 unsigned i=0;
1182 QueryUnsignedValue( &i );
1183 return i;
1184 }
1185 /// Query as a boolean. See IntValue()
BoolValue()1186 bool BoolValue() const {
1187 bool b=false;
1188 QueryBoolValue( &b );
1189 return b;
1190 }
1191 /// Query as a double. See IntValue()
DoubleValue()1192 double DoubleValue() const {
1193 double d=0;
1194 QueryDoubleValue( &d );
1195 return d;
1196 }
1197 /// Query as a float. See IntValue()
FloatValue()1198 float FloatValue() const {
1199 float f=0;
1200 QueryFloatValue( &f );
1201 return f;
1202 }
1203
1204 /** QueryIntValue interprets the attribute as an integer, and returns the value
1205 in the provided parameter. The function will return XML_SUCCESS on success,
1206 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1207 */
1208 XMLError QueryIntValue( int* value ) const;
1209 /// See QueryIntValue
1210 XMLError QueryUnsignedValue( unsigned int* value ) const;
1211 /// See QueryIntValue
1212 XMLError QueryInt64Value(int64_t* value) const;
1213 /// See QueryIntValue
1214 XMLError QueryUnsigned64Value(uint64_t* value) const;
1215 /// See QueryIntValue
1216 XMLError QueryBoolValue( bool* value ) const;
1217 /// See QueryIntValue
1218 XMLError QueryDoubleValue( double* value ) const;
1219 /// See QueryIntValue
1220 XMLError QueryFloatValue( float* value ) const;
1221
1222 /// Set the attribute to a string value.
1223 void SetAttribute( const char* value );
1224 /// Set the attribute to value.
1225 void SetAttribute( int value );
1226 /// Set the attribute to value.
1227 void SetAttribute( unsigned value );
1228 /// Set the attribute to value.
1229 void SetAttribute(int64_t value);
1230 /// Set the attribute to value.
1231 void SetAttribute(uint64_t value);
1232 /// Set the attribute to value.
1233 void SetAttribute( bool value );
1234 /// Set the attribute to value.
1235 void SetAttribute( double value );
1236 /// Set the attribute to value.
1237 void SetAttribute( float value );
1238
1239 private:
1240 enum { BUF_SIZE = 200 };
1241
XMLAttribute()1242 XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
~XMLAttribute()1243 virtual ~XMLAttribute() {}
1244
1245 XMLAttribute( const XMLAttribute& ); // not supported
1246 void operator=( const XMLAttribute& ); // not supported
1247 void SetName( const char* name );
1248
1249 char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
1250
1251 mutable StrPair _name;
1252 mutable StrPair _value;
1253 int _parseLineNum;
1254 XMLAttribute* _next;
1255 MemPool* _memPool;
1256 };
1257
1258
1259 /** The element is a container class. It has a value, the element name,
1260 and can contain other elements, text, comments, and unknowns.
1261 Elements also contain an arbitrary number of attributes.
1262 */
1263 class TINYXML2_LIB XMLElement : public XMLNode
1264 {
1265 friend class XMLDocument;
1266 public:
1267 /// Get the name of an element (which is the Value() of the node.)
Name()1268 const char* Name() const {
1269 return Value();
1270 }
1271 /// Set the name of the element.
1272 void SetName( const char* str, bool staticMem=false ) {
1273 SetValue( str, staticMem );
1274 }
1275
ToElement()1276 virtual XMLElement* ToElement() {
1277 return this;
1278 }
ToElement()1279 virtual const XMLElement* ToElement() const {
1280 return this;
1281 }
1282 virtual bool Accept( XMLVisitor* visitor ) const;
1283
1284 /** Given an attribute name, Attribute() returns the value
1285 for the attribute of that name, or null if none
1286 exists. For example:
1287
1288 @verbatim
1289 const char* value = ele->Attribute( "foo" );
1290 @endverbatim
1291
1292 The 'value' parameter is normally null. However, if specified,
1293 the attribute will only be returned if the 'name' and 'value'
1294 match. This allow you to write code:
1295
1296 @verbatim
1297 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1298 @endverbatim
1299
1300 rather than:
1301 @verbatim
1302 if ( ele->Attribute( "foo" ) ) {
1303 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1304 }
1305 @endverbatim
1306 */
1307 const char* Attribute( const char* name, const char* value=0 ) const;
1308
1309 /** Given an attribute name, IntAttribute() returns the value
1310 of the attribute interpreted as an integer. The default
1311 value will be returned if the attribute isn't present,
1312 or if there is an error. (For a method with error
1313 checking, see QueryIntAttribute()).
1314 */
1315 int IntAttribute(const char* name, int defaultValue = 0) const;
1316 /// See IntAttribute()
1317 unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
1318 /// See IntAttribute()
1319 int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
1320 /// See IntAttribute()
1321 uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const;
1322 /// See IntAttribute()
1323 bool BoolAttribute(const char* name, bool defaultValue = false) const;
1324 /// See IntAttribute()
1325 double DoubleAttribute(const char* name, double defaultValue = 0) const;
1326 /// See IntAttribute()
1327 float FloatAttribute(const char* name, float defaultValue = 0) const;
1328
1329 /** Given an attribute name, QueryIntAttribute() returns
1330 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1331 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1332 doesn't exist. If successful, the result of the conversion
1333 will be written to 'value'. If not successful, nothing will
1334 be written to 'value'. This allows you to provide default
1335 value:
1336
1337 @verbatim
1338 int value = 10;
1339 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1340 @endverbatim
1341 */
QueryIntAttribute(const char * name,int * value)1342 XMLError QueryIntAttribute( const char* name, int* value ) const {
1343 const XMLAttribute* a = FindAttribute( name );
1344 if ( !a ) {
1345 return XML_NO_ATTRIBUTE;
1346 }
1347 return a->QueryIntValue( value );
1348 }
1349
1350 /// See QueryIntAttribute()
QueryUnsignedAttribute(const char * name,unsigned int * value)1351 XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
1352 const XMLAttribute* a = FindAttribute( name );
1353 if ( !a ) {
1354 return XML_NO_ATTRIBUTE;
1355 }
1356 return a->QueryUnsignedValue( value );
1357 }
1358
1359 /// See QueryIntAttribute()
QueryInt64Attribute(const char * name,int64_t * value)1360 XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
1361 const XMLAttribute* a = FindAttribute(name);
1362 if (!a) {
1363 return XML_NO_ATTRIBUTE;
1364 }
1365 return a->QueryInt64Value(value);
1366 }
1367
1368 /// See QueryIntAttribute()
QueryUnsigned64Attribute(const char * name,uint64_t * value)1369 XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const {
1370 const XMLAttribute* a = FindAttribute(name);
1371 if(!a) {
1372 return XML_NO_ATTRIBUTE;
1373 }
1374 return a->QueryUnsigned64Value(value);
1375 }
1376
1377 /// See QueryIntAttribute()
QueryBoolAttribute(const char * name,bool * value)1378 XMLError QueryBoolAttribute( const char* name, bool* value ) const {
1379 const XMLAttribute* a = FindAttribute( name );
1380 if ( !a ) {
1381 return XML_NO_ATTRIBUTE;
1382 }
1383 return a->QueryBoolValue( value );
1384 }
1385 /// See QueryIntAttribute()
QueryDoubleAttribute(const char * name,double * value)1386 XMLError QueryDoubleAttribute( const char* name, double* value ) const {
1387 const XMLAttribute* a = FindAttribute( name );
1388 if ( !a ) {
1389 return XML_NO_ATTRIBUTE;
1390 }
1391 return a->QueryDoubleValue( value );
1392 }
1393 /// See QueryIntAttribute()
QueryFloatAttribute(const char * name,float * value)1394 XMLError QueryFloatAttribute( const char* name, float* value ) const {
1395 const XMLAttribute* a = FindAttribute( name );
1396 if ( !a ) {
1397 return XML_NO_ATTRIBUTE;
1398 }
1399 return a->QueryFloatValue( value );
1400 }
1401
1402 /// See QueryIntAttribute()
QueryStringAttribute(const char * name,const char ** value)1403 XMLError QueryStringAttribute(const char* name, const char** value) const {
1404 const XMLAttribute* a = FindAttribute(name);
1405 if (!a) {
1406 return XML_NO_ATTRIBUTE;
1407 }
1408 *value = a->Value();
1409 return XML_SUCCESS;
1410 }
1411
1412
1413
1414 /** Given an attribute name, QueryAttribute() returns
1415 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1416 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1417 doesn't exist. It is overloaded for the primitive types,
1418 and is a generally more convenient replacement of
1419 QueryIntAttribute() and related functions.
1420
1421 If successful, the result of the conversion
1422 will be written to 'value'. If not successful, nothing will
1423 be written to 'value'. This allows you to provide default
1424 value:
1425
1426 @verbatim
1427 int value = 10;
1428 QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1429 @endverbatim
1430 */
QueryAttribute(const char * name,int * value)1431 XMLError QueryAttribute( const char* name, int* value ) const {
1432 return QueryIntAttribute( name, value );
1433 }
1434
QueryAttribute(const char * name,unsigned int * value)1435 XMLError QueryAttribute( const char* name, unsigned int* value ) const {
1436 return QueryUnsignedAttribute( name, value );
1437 }
1438
QueryAttribute(const char * name,int64_t * value)1439 XMLError QueryAttribute(const char* name, int64_t* value) const {
1440 return QueryInt64Attribute(name, value);
1441 }
1442
QueryAttribute(const char * name,uint64_t * value)1443 XMLError QueryAttribute(const char* name, uint64_t* value) const {
1444 return QueryUnsigned64Attribute(name, value);
1445 }
1446
QueryAttribute(const char * name,bool * value)1447 XMLError QueryAttribute( const char* name, bool* value ) const {
1448 return QueryBoolAttribute( name, value );
1449 }
1450
QueryAttribute(const char * name,double * value)1451 XMLError QueryAttribute( const char* name, double* value ) const {
1452 return QueryDoubleAttribute( name, value );
1453 }
1454
QueryAttribute(const char * name,float * value)1455 XMLError QueryAttribute( const char* name, float* value ) const {
1456 return QueryFloatAttribute( name, value );
1457 }
1458
QueryAttribute(const char * name,const char ** value)1459 XMLError QueryAttribute(const char* name, const char** value) const {
1460 return QueryStringAttribute(name, value);
1461 }
1462
1463 /// Sets the named attribute to value.
SetAttribute(const char * name,const char * value)1464 void SetAttribute( const char* name, const char* value ) {
1465 XMLAttribute* a = FindOrCreateAttribute( name );
1466 a->SetAttribute( value );
1467 }
1468 /// Sets the named attribute to value.
SetAttribute(const char * name,int value)1469 void SetAttribute( const char* name, int value ) {
1470 XMLAttribute* a = FindOrCreateAttribute( name );
1471 a->SetAttribute( value );
1472 }
1473 /// Sets the named attribute to value.
SetAttribute(const char * name,unsigned value)1474 void SetAttribute( const char* name, unsigned value ) {
1475 XMLAttribute* a = FindOrCreateAttribute( name );
1476 a->SetAttribute( value );
1477 }
1478
1479 /// Sets the named attribute to value.
SetAttribute(const char * name,int64_t value)1480 void SetAttribute(const char* name, int64_t value) {
1481 XMLAttribute* a = FindOrCreateAttribute(name);
1482 a->SetAttribute(value);
1483 }
1484
1485 /// Sets the named attribute to value.
SetAttribute(const char * name,uint64_t value)1486 void SetAttribute(const char* name, uint64_t value) {
1487 XMLAttribute* a = FindOrCreateAttribute(name);
1488 a->SetAttribute(value);
1489 }
1490
1491 /// Sets the named attribute to value.
SetAttribute(const char * name,bool value)1492 void SetAttribute( const char* name, bool value ) {
1493 XMLAttribute* a = FindOrCreateAttribute( name );
1494 a->SetAttribute( value );
1495 }
1496 /// Sets the named attribute to value.
SetAttribute(const char * name,double value)1497 void SetAttribute( const char* name, double value ) {
1498 XMLAttribute* a = FindOrCreateAttribute( name );
1499 a->SetAttribute( value );
1500 }
1501 /// Sets the named attribute to value.
SetAttribute(const char * name,float value)1502 void SetAttribute( const char* name, float value ) {
1503 XMLAttribute* a = FindOrCreateAttribute( name );
1504 a->SetAttribute( value );
1505 }
1506
1507 /**
1508 Delete an attribute.
1509 */
1510 void DeleteAttribute( const char* name );
1511
1512 /// Return the first attribute in the list.
FirstAttribute()1513 const XMLAttribute* FirstAttribute() const {
1514 return _rootAttribute;
1515 }
1516 /// Query a specific attribute in the list.
1517 const XMLAttribute* FindAttribute( const char* name ) const;
1518
1519 /** Convenience function for easy access to the text inside an element. Although easy
1520 and concise, GetText() is limited compared to getting the XMLText child
1521 and accessing it directly.
1522
1523 If the first child of 'this' is a XMLText, the GetText()
1524 returns the character string of the Text node, else null is returned.
1525
1526 This is a convenient method for getting the text of simple contained text:
1527 @verbatim
1528 <foo>This is text</foo>
1529 const char* str = fooElement->GetText();
1530 @endverbatim
1531
1532 'str' will be a pointer to "This is text".
1533
1534 Note that this function can be misleading. If the element foo was created from
1535 this XML:
1536 @verbatim
1537 <foo><b>This is text</b></foo>
1538 @endverbatim
1539
1540 then the value of str would be null. The first child node isn't a text node, it is
1541 another element. From this XML:
1542 @verbatim
1543 <foo>This is <b>text</b></foo>
1544 @endverbatim
1545 GetText() will return "This is ".
1546 */
1547 const char* GetText() const;
1548
1549 /** Convenience function for easy access to the text inside an element. Although easy
1550 and concise, SetText() is limited compared to creating an XMLText child
1551 and mutating it directly.
1552
1553 If the first child of 'this' is a XMLText, SetText() sets its value to
1554 the given string, otherwise it will create a first child that is an XMLText.
1555
1556 This is a convenient method for setting the text of simple contained text:
1557 @verbatim
1558 <foo>This is text</foo>
1559 fooElement->SetText( "Hullaballoo!" );
1560 <foo>Hullaballoo!</foo>
1561 @endverbatim
1562
1563 Note that this function can be misleading. If the element foo was created from
1564 this XML:
1565 @verbatim
1566 <foo><b>This is text</b></foo>
1567 @endverbatim
1568
1569 then it will not change "This is text", but rather prefix it with a text element:
1570 @verbatim
1571 <foo>Hullaballoo!<b>This is text</b></foo>
1572 @endverbatim
1573
1574 For this XML:
1575 @verbatim
1576 <foo />
1577 @endverbatim
1578 SetText() will generate
1579 @verbatim
1580 <foo>Hullaballoo!</foo>
1581 @endverbatim
1582 */
1583 void SetText( const char* inText );
1584 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1585 void SetText( int value );
1586 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1587 void SetText( unsigned value );
1588 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1589 void SetText(int64_t value);
1590 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1591 void SetText(uint64_t value);
1592 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1593 void SetText( bool value );
1594 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1595 void SetText( double value );
1596 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1597 void SetText( float value );
1598
1599 /**
1600 Convenience method to query the value of a child text node. This is probably best
1601 shown by example. Given you have a document is this form:
1602 @verbatim
1603 <point>
1604 <x>1</x>
1605 <y>1.4</y>
1606 </point>
1607 @endverbatim
1608
1609 The QueryIntText() and similar functions provide a safe and easier way to get to the
1610 "value" of x and y.
1611
1612 @verbatim
1613 int x = 0;
1614 float y = 0; // types of x and y are contrived for example
1615 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1616 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1617 xElement->QueryIntText( &x );
1618 yElement->QueryFloatText( &y );
1619 @endverbatim
1620
1621 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1622 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
1623
1624 */
1625 XMLError QueryIntText( int* ival ) const;
1626 /// See QueryIntText()
1627 XMLError QueryUnsignedText( unsigned* uval ) const;
1628 /// See QueryIntText()
1629 XMLError QueryInt64Text(int64_t* uval) const;
1630 /// See QueryIntText()
1631 XMLError QueryUnsigned64Text(uint64_t* uval) const;
1632 /// See QueryIntText()
1633 XMLError QueryBoolText( bool* bval ) const;
1634 /// See QueryIntText()
1635 XMLError QueryDoubleText( double* dval ) const;
1636 /// See QueryIntText()
1637 XMLError QueryFloatText( float* fval ) const;
1638
1639 int IntText(int defaultValue = 0) const;
1640
1641 /// See QueryIntText()
1642 unsigned UnsignedText(unsigned defaultValue = 0) const;
1643 /// See QueryIntText()
1644 int64_t Int64Text(int64_t defaultValue = 0) const;
1645 /// See QueryIntText()
1646 uint64_t Unsigned64Text(uint64_t defaultValue = 0) const;
1647 /// See QueryIntText()
1648 bool BoolText(bool defaultValue = false) const;
1649 /// See QueryIntText()
1650 double DoubleText(double defaultValue = 0) const;
1651 /// See QueryIntText()
1652 float FloatText(float defaultValue = 0) const;
1653
1654 /**
1655 Convenience method to create a new XMLElement and add it as last (right)
1656 child of this node. Returns the created and inserted element.
1657 */
1658 XMLElement* InsertNewChildElement(const char* name);
1659 /// See InsertNewChildElement()
1660 XMLComment* InsertNewComment(const char* comment);
1661 /// See InsertNewChildElement()
1662 XMLText* InsertNewText(const char* text);
1663 /// See InsertNewChildElement()
1664 XMLDeclaration* InsertNewDeclaration(const char* text);
1665 /// See InsertNewChildElement()
1666 XMLUnknown* InsertNewUnknown(const char* text);
1667
1668
1669 // internal:
1670 enum ElementClosingType {
1671 OPEN, // <foo>
1672 CLOSED, // <foo/>
1673 CLOSING // </foo>
1674 };
ClosingType()1675 ElementClosingType ClosingType() const {
1676 return _closingType;
1677 }
1678 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1679 virtual bool ShallowEqual( const XMLNode* compare ) const;
1680
1681 protected:
1682 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1683
1684 private:
1685 XMLElement( XMLDocument* doc );
1686 virtual ~XMLElement();
1687 XMLElement( const XMLElement& ); // not supported
1688 void operator=( const XMLElement& ); // not supported
1689
1690 XMLAttribute* FindOrCreateAttribute( const char* name );
1691 char* ParseAttributes( char* p, int* curLineNumPtr );
1692 static void DeleteAttribute( XMLAttribute* attribute );
1693 XMLAttribute* CreateAttribute();
1694
1695 enum { BUF_SIZE = 200 };
1696 ElementClosingType _closingType;
1697 // The attribute list is ordered; there is no 'lastAttribute'
1698 // because the list needs to be scanned for dupes before adding
1699 // a new attribute.
1700 XMLAttribute* _rootAttribute;
1701 };
1702
1703
1704 enum Whitespace {
1705 PRESERVE_WHITESPACE,
1706 COLLAPSE_WHITESPACE
1707 };
1708
1709
1710 /** A Document binds together all the functionality.
1711 It can be saved, loaded, and printed to the screen.
1712 All Nodes are connected and allocated to a Document.
1713 If the Document is deleted, all its Nodes are also deleted.
1714 */
1715 class TINYXML2_LIB XMLDocument : public XMLNode
1716 {
1717 friend class XMLElement;
1718 // Gives access to SetError and Push/PopDepth, but over-access for everything else.
1719 // Wishing C++ had "internal" scope.
1720 friend class XMLNode;
1721 friend class XMLText;
1722 friend class XMLComment;
1723 friend class XMLDeclaration;
1724 friend class XMLUnknown;
1725 public:
1726 /// constructor
1727 XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
1728 ~XMLDocument();
1729
ToDocument()1730 virtual XMLDocument* ToDocument() {
1731 TIXMLASSERT( this == _document );
1732 return this;
1733 }
ToDocument()1734 virtual const XMLDocument* ToDocument() const {
1735 TIXMLASSERT( this == _document );
1736 return this;
1737 }
1738
1739 /**
1740 Parse an XML file from a character string.
1741 Returns XML_SUCCESS (0) on success, or
1742 an errorID.
1743
1744 You may optionally pass in the 'nBytes', which is
1745 the number of bytes which will be parsed. If not
1746 specified, TinyXML-2 will assume 'xml' points to a
1747 null terminated string.
1748 */
1749 XMLError Parse( const char* xml, size_t nBytes=static_cast<size_t>(-1) );
1750
1751 /**
1752 Load an XML file from disk.
1753 Returns XML_SUCCESS (0) on success, or
1754 an errorID.
1755 */
1756 XMLError LoadFile( const char* filename );
1757
1758 /**
1759 Load an XML file from disk. You are responsible
1760 for providing and closing the FILE*.
1761
1762 NOTE: The file should be opened as binary ("rb")
1763 not text in order for TinyXML-2 to correctly
1764 do newline normalization.
1765
1766 Returns XML_SUCCESS (0) on success, or
1767 an errorID.
1768 */
1769 XMLError LoadFile( FILE* );
1770
1771 /**
1772 Save the XML file to disk.
1773 Returns XML_SUCCESS (0) on success, or
1774 an errorID.
1775 */
1776 XMLError SaveFile( const char* filename, bool compact = false );
1777
1778 /**
1779 Save the XML file to disk. You are responsible
1780 for providing and closing the FILE*.
1781
1782 Returns XML_SUCCESS (0) on success, or
1783 an errorID.
1784 */
1785 XMLError SaveFile( FILE* fp, bool compact = false );
1786
ProcessEntities()1787 bool ProcessEntities() const {
1788 return _processEntities;
1789 }
WhitespaceMode()1790 Whitespace WhitespaceMode() const {
1791 return _whitespaceMode;
1792 }
1793
1794 /**
1795 Returns true if this document has a leading Byte Order Mark of UTF8.
1796 */
HasBOM()1797 bool HasBOM() const {
1798 return _writeBOM;
1799 }
1800 /** Sets whether to write the BOM when writing the file.
1801 */
SetBOM(bool useBOM)1802 void SetBOM( bool useBOM ) {
1803 _writeBOM = useBOM;
1804 }
1805
1806 /** Return the root element of DOM. Equivalent to FirstChildElement().
1807 To get the first node, use FirstChild().
1808 */
RootElement()1809 XMLElement* RootElement() {
1810 return FirstChildElement();
1811 }
RootElement()1812 const XMLElement* RootElement() const {
1813 return FirstChildElement();
1814 }
1815
1816 /** Print the Document. If the Printer is not provided, it will
1817 print to stdout. If you provide Printer, this can print to a file:
1818 @verbatim
1819 XMLPrinter printer( fp );
1820 doc.Print( &printer );
1821 @endverbatim
1822
1823 Or you can use a printer to print to memory:
1824 @verbatim
1825 XMLPrinter printer;
1826 doc.Print( &printer );
1827 // printer.CStr() has a const char* to the XML
1828 @endverbatim
1829 */
1830 void Print( XMLPrinter* streamer=0 ) const;
1831 virtual bool Accept( XMLVisitor* visitor ) const;
1832
1833 /**
1834 Create a new Element associated with
1835 this Document. The memory for the Element
1836 is managed by the Document.
1837 */
1838 XMLElement* NewElement( const char* name );
1839 /**
1840 Create a new Comment associated with
1841 this Document. The memory for the Comment
1842 is managed by the Document.
1843 */
1844 XMLComment* NewComment( const char* comment );
1845 /**
1846 Create a new Text associated with
1847 this Document. The memory for the Text
1848 is managed by the Document.
1849 */
1850 XMLText* NewText( const char* text );
1851 /**
1852 Create a new Declaration associated with
1853 this Document. The memory for the object
1854 is managed by the Document.
1855
1856 If the 'text' param is null, the standard
1857 declaration is used.:
1858 @verbatim
1859 <?xml version="1.0" encoding="UTF-8"?>
1860 @endverbatim
1861 */
1862 XMLDeclaration* NewDeclaration( const char* text=0 );
1863 /**
1864 Create a new Unknown associated with
1865 this Document. The memory for the object
1866 is managed by the Document.
1867 */
1868 XMLUnknown* NewUnknown( const char* text );
1869
1870 /**
1871 Delete a node associated with this document.
1872 It will be unlinked from the DOM.
1873 */
1874 void DeleteNode( XMLNode* node );
1875
ClearError()1876 void ClearError() {
1877 SetError(XML_SUCCESS, 0, 0);
1878 }
1879
1880 /// Return true if there was an error parsing the document.
Error()1881 bool Error() const {
1882 return _errorID != XML_SUCCESS;
1883 }
1884 /// Return the errorID.
ErrorID()1885 XMLError ErrorID() const {
1886 return _errorID;
1887 }
1888 const char* ErrorName() const;
1889 static const char* ErrorIDToName(XMLError errorID);
1890
1891 /** Returns a "long form" error description. A hopefully helpful
1892 diagnostic with location, line number, and/or additional info.
1893 */
1894 const char* ErrorStr() const;
1895
1896 /// A (trivial) utility function that prints the ErrorStr() to stdout.
1897 void PrintError() const;
1898
1899 /// Return the line where the error occurred, or zero if unknown.
ErrorLineNum()1900 int ErrorLineNum() const
1901 {
1902 return _errorLineNum;
1903 }
1904
1905 /// Clear the document, resetting it to the initial state.
1906 void Clear();
1907
1908 /**
1909 Copies this document to a target document.
1910 The target will be completely cleared before the copy.
1911 If you want to copy a sub-tree, see XMLNode::DeepClone().
1912
1913 NOTE: that the 'target' must be non-null.
1914 */
1915 void DeepCopy(XMLDocument* target) const;
1916
1917 // internal
1918 char* Identify( char* p, XMLNode** node );
1919
1920 // internal
1921 void MarkInUse(const XMLNode* const);
1922
ShallowClone(XMLDocument *)1923 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
1924 return 0;
1925 }
ShallowEqual(const XMLNode *)1926 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
1927 return false;
1928 }
1929
1930 private:
1931 XMLDocument( const XMLDocument& ); // not supported
1932 void operator=( const XMLDocument& ); // not supported
1933
1934 bool _writeBOM;
1935 bool _processEntities;
1936 XMLError _errorID;
1937 Whitespace _whitespaceMode;
1938 mutable StrPair _errorStr;
1939 int _errorLineNum;
1940 char* _charBuffer;
1941 int _parseCurLineNum;
1942 int _parsingDepth;
1943 // Memory tracking does add some overhead.
1944 // However, the code assumes that you don't
1945 // have a bunch of unlinked nodes around.
1946 // Therefore it takes less memory to track
1947 // in the document vs. a linked list in the XMLNode,
1948 // and the performance is the same.
1949 DynArray<XMLNode*, 10> _unlinked;
1950
1951 MemPoolT< sizeof(XMLElement) > _elementPool;
1952 MemPoolT< sizeof(XMLAttribute) > _attributePool;
1953 MemPoolT< sizeof(XMLText) > _textPool;
1954 MemPoolT< sizeof(XMLComment) > _commentPool;
1955
1956 static const char* _errorNames[XML_ERROR_COUNT];
1957
1958 void Parse();
1959
1960 void SetError( XMLError error, int lineNum, const char* format, ... );
1961
1962 // Something of an obvious security hole, once it was discovered.
1963 // Either an ill-formed XML or an excessively deep one can overflow
1964 // the stack. Track stack depth, and error out if needed.
1965 class DepthTracker {
1966 public:
DepthTracker(XMLDocument * document)1967 explicit DepthTracker(XMLDocument * document) {
1968 this->_document = document;
1969 document->PushDepth();
1970 }
~DepthTracker()1971 ~DepthTracker() {
1972 _document->PopDepth();
1973 }
1974 private:
1975 XMLDocument * _document;
1976 };
1977 void PushDepth();
1978 void PopDepth();
1979
1980 template<class NodeType, int PoolElementSize>
1981 NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
1982 };
1983
1984 template<class NodeType, int PoolElementSize>
CreateUnlinkedNode(MemPoolT<PoolElementSize> & pool)1985 inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
1986 {
1987 TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
1988 TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
1989 NodeType* returnNode = new (pool.Alloc()) NodeType( this );
1990 TIXMLASSERT( returnNode );
1991 returnNode->_memPool = &pool;
1992
1993 _unlinked.Push(returnNode);
1994 return returnNode;
1995 }
1996
1997 /**
1998 A XMLHandle is a class that wraps a node pointer with null checks; this is
1999 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
2000 DOM structure. It is a separate utility class.
2001
2002 Take an example:
2003 @verbatim
2004 <Document>
2005 <Element attributeA = "valueA">
2006 <Child attributeB = "value1" />
2007 <Child attributeB = "value2" />
2008 </Element>
2009 </Document>
2010 @endverbatim
2011
2012 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
2013 easy to write a *lot* of code that looks like:
2014
2015 @verbatim
2016 XMLElement* root = document.FirstChildElement( "Document" );
2017 if ( root )
2018 {
2019 XMLElement* element = root->FirstChildElement( "Element" );
2020 if ( element )
2021 {
2022 XMLElement* child = element->FirstChildElement( "Child" );
2023 if ( child )
2024 {
2025 XMLElement* child2 = child->NextSiblingElement( "Child" );
2026 if ( child2 )
2027 {
2028 // Finally do something useful.
2029 @endverbatim
2030
2031 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
2032 of such code. A XMLHandle checks for null pointers so it is perfectly safe
2033 and correct to use:
2034
2035 @verbatim
2036 XMLHandle docHandle( &document );
2037 XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
2038 if ( child2 )
2039 {
2040 // do something useful
2041 @endverbatim
2042
2043 Which is MUCH more concise and useful.
2044
2045 It is also safe to copy handles - internally they are nothing more than node pointers.
2046 @verbatim
2047 XMLHandle handleCopy = handle;
2048 @endverbatim
2049
2050 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
2051 */
2052 class TINYXML2_LIB XMLHandle
2053 {
2054 public:
2055 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
XMLHandle(XMLNode * node)2056 explicit XMLHandle( XMLNode* node ) : _node( node ) {
2057 }
2058 /// Create a handle from a node.
XMLHandle(XMLNode & node)2059 explicit XMLHandle( XMLNode& node ) : _node( &node ) {
2060 }
2061 /// Copy constructor
XMLHandle(const XMLHandle & ref)2062 XMLHandle( const XMLHandle& ref ) : _node( ref._node ) {
2063 }
2064 /// Assignment
2065 XMLHandle& operator=( const XMLHandle& ref ) {
2066 _node = ref._node;
2067 return *this;
2068 }
2069
2070 /// Get the first child of this handle.
FirstChild()2071 XMLHandle FirstChild() {
2072 return XMLHandle( _node ? _node->FirstChild() : 0 );
2073 }
2074 /// Get the first child element of this handle.
2075 XMLHandle FirstChildElement( const char* name = 0 ) {
2076 return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
2077 }
2078 /// Get the last child of this handle.
LastChild()2079 XMLHandle LastChild() {
2080 return XMLHandle( _node ? _node->LastChild() : 0 );
2081 }
2082 /// Get the last child element of this handle.
2083 XMLHandle LastChildElement( const char* name = 0 ) {
2084 return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
2085 }
2086 /// Get the previous sibling of this handle.
PreviousSibling()2087 XMLHandle PreviousSibling() {
2088 return XMLHandle( _node ? _node->PreviousSibling() : 0 );
2089 }
2090 /// Get the previous sibling element of this handle.
2091 XMLHandle PreviousSiblingElement( const char* name = 0 ) {
2092 return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
2093 }
2094 /// Get the next sibling of this handle.
NextSibling()2095 XMLHandle NextSibling() {
2096 return XMLHandle( _node ? _node->NextSibling() : 0 );
2097 }
2098 /// Get the next sibling element of this handle.
2099 XMLHandle NextSiblingElement( const char* name = 0 ) {
2100 return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
2101 }
2102
2103 /// Safe cast to XMLNode. This can return null.
ToNode()2104 XMLNode* ToNode() {
2105 return _node;
2106 }
2107 /// Safe cast to XMLElement. This can return null.
ToElement()2108 XMLElement* ToElement() {
2109 return ( _node ? _node->ToElement() : 0 );
2110 }
2111 /// Safe cast to XMLText. This can return null.
ToText()2112 XMLText* ToText() {
2113 return ( _node ? _node->ToText() : 0 );
2114 }
2115 /// Safe cast to XMLUnknown. This can return null.
ToUnknown()2116 XMLUnknown* ToUnknown() {
2117 return ( _node ? _node->ToUnknown() : 0 );
2118 }
2119 /// Safe cast to XMLDeclaration. This can return null.
ToDeclaration()2120 XMLDeclaration* ToDeclaration() {
2121 return ( _node ? _node->ToDeclaration() : 0 );
2122 }
2123
2124 private:
2125 XMLNode* _node;
2126 };
2127
2128
2129 /**
2130 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
2131 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
2132 */
2133 class TINYXML2_LIB XMLConstHandle
2134 {
2135 public:
XMLConstHandle(const XMLNode * node)2136 explicit XMLConstHandle( const XMLNode* node ) : _node( node ) {
2137 }
XMLConstHandle(const XMLNode & node)2138 explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) {
2139 }
XMLConstHandle(const XMLConstHandle & ref)2140 XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) {
2141 }
2142
2143 XMLConstHandle& operator=( const XMLConstHandle& ref ) {
2144 _node = ref._node;
2145 return *this;
2146 }
2147
FirstChild()2148 const XMLConstHandle FirstChild() const {
2149 return XMLConstHandle( _node ? _node->FirstChild() : 0 );
2150 }
2151 const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
2152 return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
2153 }
LastChild()2154 const XMLConstHandle LastChild() const {
2155 return XMLConstHandle( _node ? _node->LastChild() : 0 );
2156 }
2157 const XMLConstHandle LastChildElement( const char* name = 0 ) const {
2158 return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
2159 }
PreviousSibling()2160 const XMLConstHandle PreviousSibling() const {
2161 return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
2162 }
2163 const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
2164 return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
2165 }
NextSibling()2166 const XMLConstHandle NextSibling() const {
2167 return XMLConstHandle( _node ? _node->NextSibling() : 0 );
2168 }
2169 const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
2170 return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
2171 }
2172
2173
ToNode()2174 const XMLNode* ToNode() const {
2175 return _node;
2176 }
ToElement()2177 const XMLElement* ToElement() const {
2178 return ( _node ? _node->ToElement() : 0 );
2179 }
ToText()2180 const XMLText* ToText() const {
2181 return ( _node ? _node->ToText() : 0 );
2182 }
ToUnknown()2183 const XMLUnknown* ToUnknown() const {
2184 return ( _node ? _node->ToUnknown() : 0 );
2185 }
ToDeclaration()2186 const XMLDeclaration* ToDeclaration() const {
2187 return ( _node ? _node->ToDeclaration() : 0 );
2188 }
2189
2190 private:
2191 const XMLNode* _node;
2192 };
2193
2194
2195 /**
2196 Printing functionality. The XMLPrinter gives you more
2197 options than the XMLDocument::Print() method.
2198
2199 It can:
2200 -# Print to memory.
2201 -# Print to a file you provide.
2202 -# Print XML without a XMLDocument.
2203
2204 Print to Memory
2205
2206 @verbatim
2207 XMLPrinter printer;
2208 doc.Print( &printer );
2209 SomeFunction( printer.CStr() );
2210 @endverbatim
2211
2212 Print to a File
2213
2214 You provide the file pointer.
2215 @verbatim
2216 XMLPrinter printer( fp );
2217 doc.Print( &printer );
2218 @endverbatim
2219
2220 Print without a XMLDocument
2221
2222 When loading, an XML parser is very useful. However, sometimes
2223 when saving, it just gets in the way. The code is often set up
2224 for streaming, and constructing the DOM is just overhead.
2225
2226 The Printer supports the streaming case. The following code
2227 prints out a trivially simple XML file without ever creating
2228 an XML document.
2229
2230 @verbatim
2231 XMLPrinter printer( fp );
2232 printer.OpenElement( "foo" );
2233 printer.PushAttribute( "foo", "bar" );
2234 printer.CloseElement();
2235 @endverbatim
2236 */
2237 class TINYXML2_LIB XMLPrinter : public XMLVisitor
2238 {
2239 public:
2240 /** Construct the printer. If the FILE* is specified,
2241 this will print to the FILE. Else it will print
2242 to memory, and the result is available in CStr().
2243 If 'compact' is set to true, then output is created
2244 with only required whitespace and newlines.
2245 */
2246 XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
~XMLPrinter()2247 virtual ~XMLPrinter() {}
2248
2249 /** If streaming, write the BOM and declaration. */
2250 void PushHeader( bool writeBOM, bool writeDeclaration );
2251 /** If streaming, start writing an element.
2252 The element must be closed with CloseElement()
2253 */
2254 void OpenElement( const char* name, bool compactMode=false );
2255 /// If streaming, add an attribute to an open element.
2256 void PushAttribute( const char* name, const char* value );
2257 void PushAttribute( const char* name, int value );
2258 void PushAttribute( const char* name, unsigned value );
2259 void PushAttribute( const char* name, int64_t value );
2260 void PushAttribute( const char* name, uint64_t value );
2261 void PushAttribute( const char* name, bool value );
2262 void PushAttribute( const char* name, double value );
2263 /// If streaming, close the Element.
2264 virtual void CloseElement( bool compactMode=false );
2265
2266 /// Add a text node.
2267 void PushText( const char* text, bool cdata=false );
2268 /// Add a text node from an integer.
2269 void PushText( int value );
2270 /// Add a text node from an unsigned.
2271 void PushText( unsigned value );
2272 /// Add a text node from a signed 64bit integer.
2273 void PushText( int64_t value );
2274 /// Add a text node from an unsigned 64bit integer.
2275 void PushText( uint64_t value );
2276 /// Add a text node from a bool.
2277 void PushText( bool value );
2278 /// Add a text node from a float.
2279 void PushText( float value );
2280 /// Add a text node from a double.
2281 void PushText( double value );
2282
2283 /// Add a comment
2284 void PushComment( const char* comment );
2285
2286 void PushDeclaration( const char* value );
2287 void PushUnknown( const char* value );
2288
2289 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
VisitExit(const XMLDocument &)2290 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
2291 return true;
2292 }
2293
2294 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
2295 virtual bool VisitExit( const XMLElement& element );
2296
2297 virtual bool Visit( const XMLText& text );
2298 virtual bool Visit( const XMLComment& comment );
2299 virtual bool Visit( const XMLDeclaration& declaration );
2300 virtual bool Visit( const XMLUnknown& unknown );
2301
2302 /**
2303 If in print to memory mode, return a pointer to
2304 the XML file in memory.
2305 */
CStr()2306 const char* CStr() const {
2307 return _buffer.Mem();
2308 }
2309 /**
2310 If in print to memory mode, return the size
2311 of the XML file in memory. (Note the size returned
2312 includes the terminating null.)
2313 */
CStrSize()2314 int CStrSize() const {
2315 return _buffer.Size();
2316 }
2317 /**
2318 If in print to memory mode, reset the buffer to the
2319 beginning.
2320 */
2321 void ClearBuffer( bool resetToFirstElement = true ) {
2322 _buffer.Clear();
2323 _buffer.Push(0);
2324 _firstElement = resetToFirstElement;
2325 }
2326
2327 protected:
CompactMode(const XMLElement &)2328 virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
2329
2330 /** Prints out the space before an element. You may override to change
2331 the space and tabs used. A PrintSpace() override should call Print().
2332 */
2333 virtual void PrintSpace( int depth );
2334 virtual void Print( const char* format, ... );
2335 virtual void Write( const char* data, size_t size );
2336 virtual void Putc( char ch );
2337
Write(const char * data)2338 inline void Write(const char* data) { Write(data, strlen(data)); }
2339
2340 void SealElementIfJustOpened();
2341 bool _elementJustOpened;
2342 DynArray< const char*, 10 > _stack;
2343
2344 private:
2345 /**
2346 Prepares to write a new node. This includes sealing an element that was
2347 just opened, and writing any whitespace necessary if not in compact mode.
2348 */
2349 void PrepareForNewNode( bool compactMode );
2350 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
2351
2352 bool _firstElement;
2353 FILE* _fp;
2354 int _depth;
2355 int _textDepth;
2356 bool _processEntities;
2357 bool _compactMode;
2358
2359 enum {
2360 ENTITY_RANGE = 64,
2361 BUF_SIZE = 200
2362 };
2363 bool _entityFlag[ENTITY_RANGE];
2364 bool _restrictedEntityFlag[ENTITY_RANGE];
2365
2366 DynArray< char, 20 > _buffer;
2367
2368 // Prohibit cloning, intentionally not implemented
2369 XMLPrinter( const XMLPrinter& );
2370 XMLPrinter& operator=( const XMLPrinter& );
2371 };
2372
2373
2374 } // tinyxml2
2375
2376 #if defined(_MSC_VER)
2377 # pragma warning(pop)
2378 #endif
2379
2380 #endif // TINYXML2_INCLUDED
2381