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
593 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
594 if ( p == q ) {
595 return true;
596 }
597 TIXMLASSERT( p );
598 TIXMLASSERT( q );
599 TIXMLASSERT( nChar >= 0 );
600 return strncmp( p, q, nChar ) == 0;
601 }
602
IsUTF8Continuation(const char p)603 inline static bool IsUTF8Continuation( const char p ) {
604 return ( p & 0x80 ) != 0;
605 }
606
607 static const char* ReadBOM( const char* p, bool* hasBOM );
608 // p is the starting location,
609 // the UTF-8 value of the entity will be placed in value, and length filled in.
610 static const char* GetCharacterRef( const char* p, char* value, int* length );
611 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
612
613 // converts primitive types to strings
614 static void ToStr( int v, char* buffer, int bufferSize );
615 static void ToStr( unsigned v, char* buffer, int bufferSize );
616 static void ToStr( bool v, char* buffer, int bufferSize );
617 static void ToStr( float v, char* buffer, int bufferSize );
618 static void ToStr( double v, char* buffer, int bufferSize );
619 static void ToStr(int64_t v, char* buffer, int bufferSize);
620 static void ToStr(uint64_t v, char* buffer, int bufferSize);
621
622 // converts strings to primitive types
623 static bool ToInt( const char* str, int* value );
624 static bool ToUnsigned( const char* str, unsigned* value );
625 static bool ToBool( const char* str, bool* value );
626 static bool ToFloat( const char* str, float* value );
627 static bool ToDouble( const char* str, double* value );
628 static bool ToInt64(const char* str, int64_t* value);
629 static bool ToUnsigned64(const char* str, uint64_t* value);
630 // Changes what is serialized for a boolean value.
631 // Default to "true" and "false". Shouldn't be changed
632 // unless you have a special testing or compatibility need.
633 // Be careful: static, global, & not thread safe.
634 // Be sure to set static const memory as parameters.
635 static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
636
637 private:
638 static const char* writeBoolTrue;
639 static const char* writeBoolFalse;
640 };
641
642
643 /** XMLNode is a base class for every object that is in the
644 XML Document Object Model (DOM), except XMLAttributes.
645 Nodes have siblings, a parent, and children which can
646 be navigated. A node is always in a XMLDocument.
647 The type of a XMLNode can be queried, and it can
648 be cast to its more defined type.
649
650 A XMLDocument allocates memory for all its Nodes.
651 When the XMLDocument gets deleted, all its Nodes
652 will also be deleted.
653
654 @verbatim
655 A Document can contain: Element (container or leaf)
656 Comment (leaf)
657 Unknown (leaf)
658 Declaration( leaf )
659
660 An Element can contain: Element (container or leaf)
661 Text (leaf)
662 Attributes (not on tree)
663 Comment (leaf)
664 Unknown (leaf)
665
666 @endverbatim
667 */
668 class TINYXML2_LIB XMLNode
669 {
670 friend class XMLDocument;
671 friend class XMLElement;
672 public:
673
674 /// Get the XMLDocument that owns this XMLNode.
GetDocument()675 const XMLDocument* GetDocument() const {
676 TIXMLASSERT( _document );
677 return _document;
678 }
679 /// Get the XMLDocument that owns this XMLNode.
GetDocument()680 XMLDocument* GetDocument() {
681 TIXMLASSERT( _document );
682 return _document;
683 }
684
685 /// Safely cast to an Element, or null.
ToElement()686 virtual XMLElement* ToElement() {
687 return 0;
688 }
689 /// Safely cast to Text, or null.
ToText()690 virtual XMLText* ToText() {
691 return 0;
692 }
693 /// Safely cast to a Comment, or null.
ToComment()694 virtual XMLComment* ToComment() {
695 return 0;
696 }
697 /// Safely cast to a Document, or null.
ToDocument()698 virtual XMLDocument* ToDocument() {
699 return 0;
700 }
701 /// Safely cast to a Declaration, or null.
ToDeclaration()702 virtual XMLDeclaration* ToDeclaration() {
703 return 0;
704 }
705 /// Safely cast to an Unknown, or null.
ToUnknown()706 virtual XMLUnknown* ToUnknown() {
707 return 0;
708 }
709
ToElement()710 virtual const XMLElement* ToElement() const {
711 return 0;
712 }
ToText()713 virtual const XMLText* ToText() const {
714 return 0;
715 }
ToComment()716 virtual const XMLComment* ToComment() const {
717 return 0;
718 }
ToDocument()719 virtual const XMLDocument* ToDocument() const {
720 return 0;
721 }
ToDeclaration()722 virtual const XMLDeclaration* ToDeclaration() const {
723 return 0;
724 }
ToUnknown()725 virtual const XMLUnknown* ToUnknown() const {
726 return 0;
727 }
728
729 /** The meaning of 'value' changes for the specific type.
730 @verbatim
731 Document: empty (NULL is returned, not an empty string)
732 Element: name of the element
733 Comment: the comment text
734 Unknown: the tag contents
735 Text: the text string
736 @endverbatim
737 */
738 const char* Value() const;
739
740 /** Set the Value of an XML node.
741 @sa Value()
742 */
743 void SetValue( const char* val, bool staticMem=false );
744
745 /// Gets the line number the node is in, if the document was parsed from a file.
GetLineNum()746 int GetLineNum() const { return _parseLineNum; }
747
748 /// Get the parent of this node on the DOM.
Parent()749 const XMLNode* Parent() const {
750 return _parent;
751 }
752
Parent()753 XMLNode* Parent() {
754 return _parent;
755 }
756
757 /// Returns true if this node has no children.
NoChildren()758 bool NoChildren() const {
759 return !_firstChild;
760 }
761
762 /// Get the first child node, or null if none exists.
FirstChild()763 const XMLNode* FirstChild() const {
764 return _firstChild;
765 }
766
FirstChild()767 XMLNode* FirstChild() {
768 return _firstChild;
769 }
770
771 /** Get the first child element, or optionally the first child
772 element with the specified name.
773 */
774 const XMLElement* FirstChildElement( const char* name = 0 ) const;
775
776 XMLElement* FirstChildElement( const char* name = 0 ) {
777 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
778 }
779
780 /// Get the last child node, or null if none exists.
LastChild()781 const XMLNode* LastChild() const {
782 return _lastChild;
783 }
784
LastChild()785 XMLNode* LastChild() {
786 return _lastChild;
787 }
788
789 /** Get the last child element or optionally the last child
790 element with the specified name.
791 */
792 const XMLElement* LastChildElement( const char* name = 0 ) const;
793
794 XMLElement* LastChildElement( const char* name = 0 ) {
795 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
796 }
797
798 /// Get the previous (left) sibling node of this node.
PreviousSibling()799 const XMLNode* PreviousSibling() const {
800 return _prev;
801 }
802
PreviousSibling()803 XMLNode* PreviousSibling() {
804 return _prev;
805 }
806
807 /// Get the previous (left) sibling element of this node, with an optionally supplied name.
808 const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
809
810 XMLElement* PreviousSiblingElement( const char* name = 0 ) {
811 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
812 }
813
814 /// Get the next (right) sibling node of this node.
NextSibling()815 const XMLNode* NextSibling() const {
816 return _next;
817 }
818
NextSibling()819 XMLNode* NextSibling() {
820 return _next;
821 }
822
823 /// Get the next (right) sibling element of this node, with an optionally supplied name.
824 const XMLElement* NextSiblingElement( const char* name = 0 ) const;
825
826 XMLElement* NextSiblingElement( const char* name = 0 ) {
827 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
828 }
829
830 /**
831 Add a child node as the last (right) child.
832 If the child node is already part of the document,
833 it is moved from its old location to the new location.
834 Returns the addThis argument or 0 if the node does not
835 belong to the same document.
836 */
837 XMLNode* InsertEndChild( XMLNode* addThis );
838
LinkEndChild(XMLNode * addThis)839 XMLNode* LinkEndChild( XMLNode* addThis ) {
840 return InsertEndChild( addThis );
841 }
842 /**
843 Add a child node as the first (left) child.
844 If the child node is already part of the document,
845 it is moved from its old location to the new location.
846 Returns the addThis argument or 0 if the node does not
847 belong to the same document.
848 */
849 XMLNode* InsertFirstChild( XMLNode* addThis );
850 /**
851 Add a node after the specified child node.
852 If the child node is already part of the document,
853 it is moved from its old location to the new location.
854 Returns the addThis argument or 0 if the afterThis node
855 is not a child of this node, or if the node does not
856 belong to the same document.
857 */
858 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
859
860 /**
861 Delete all the children of this node.
862 */
863 void DeleteChildren();
864
865 /**
866 Delete a child of this node.
867 */
868 void DeleteChild( XMLNode* node );
869
870 /**
871 Make a copy of this node, but not its children.
872 You may pass in a Document pointer that will be
873 the owner of the new Node. If the 'document' is
874 null, then the node returned will be allocated
875 from the current Document. (this->GetDocument())
876
877 Note: if called on a XMLDocument, this will return null.
878 */
879 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
880
881 /**
882 Make a copy of this node and all its children.
883
884 If the 'target' is null, then the nodes will
885 be allocated in the current document. If 'target'
886 is specified, the memory will be allocated is the
887 specified XMLDocument.
888
889 NOTE: This is probably not the correct tool to
890 copy a document, since XMLDocuments can have multiple
891 top level XMLNodes. You probably want to use
892 XMLDocument::DeepCopy()
893 */
894 XMLNode* DeepClone( XMLDocument* target ) const;
895
896 /**
897 Test if 2 nodes are the same, but don't test children.
898 The 2 nodes do not need to be in the same Document.
899
900 Note: if called on a XMLDocument, this will return false.
901 */
902 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
903
904 /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
905 XML tree will be conditionally visited and the host will be called back
906 via the XMLVisitor interface.
907
908 This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
909 the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
910 interface versus any other.)
911
912 The interface has been based on ideas from:
913
914 - http://www.saxproject.org/
915 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
916
917 Which are both good references for "visiting".
918
919 An example of using Accept():
920 @verbatim
921 XMLPrinter printer;
922 tinyxmlDoc.Accept( &printer );
923 const char* xmlcstr = printer.CStr();
924 @endverbatim
925 */
926 virtual bool Accept( XMLVisitor* visitor ) const = 0;
927
928 /**
929 Set user data into the XMLNode. TinyXML-2 in
930 no way processes or interprets user data.
931 It is initially 0.
932 */
SetUserData(void * userData)933 void SetUserData(void* userData) { _userData = userData; }
934
935 /**
936 Get user data set into the XMLNode. TinyXML-2 in
937 no way processes or interprets user data.
938 It is initially 0.
939 */
GetUserData()940 void* GetUserData() const { return _userData; }
941
942 protected:
943 explicit XMLNode( XMLDocument* );
944 virtual ~XMLNode();
945
946 virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
947
948 XMLDocument* _document;
949 XMLNode* _parent;
950 mutable StrPair _value;
951 int _parseLineNum;
952
953 XMLNode* _firstChild;
954 XMLNode* _lastChild;
955
956 XMLNode* _prev;
957 XMLNode* _next;
958
959 void* _userData;
960
961 private:
962 MemPool* _memPool;
963 void Unlink( XMLNode* child );
964 static void DeleteNode( XMLNode* node );
965 void InsertChildPreamble( XMLNode* insertThis ) const;
966 const XMLElement* ToElementWithName( const char* name ) const;
967
968 XMLNode( const XMLNode& ); // not supported
969 XMLNode& operator=( const XMLNode& ); // not supported
970 };
971
972
973 /** XML text.
974
975 Note that a text node can have child element nodes, for example:
976 @verbatim
977 <root>This is <b>bold</b></root>
978 @endverbatim
979
980 A text node can have 2 ways to output the next. "normal" output
981 and CDATA. It will default to the mode it was parsed from the XML file and
982 you generally want to leave it alone, but you can change the output mode with
983 SetCData() and query it with CData().
984 */
985 class TINYXML2_LIB XMLText : public XMLNode
986 {
987 friend class XMLDocument;
988 public:
989 virtual bool Accept( XMLVisitor* visitor ) const;
990
ToText()991 virtual XMLText* ToText() {
992 return this;
993 }
ToText()994 virtual const XMLText* ToText() const {
995 return this;
996 }
997
998 /// Declare whether this should be CDATA or standard text.
SetCData(bool isCData)999 void SetCData( bool isCData ) {
1000 _isCData = isCData;
1001 }
1002 /// Returns true if this is a CDATA text element.
CData()1003 bool CData() const {
1004 return _isCData;
1005 }
1006
1007 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1008 virtual bool ShallowEqual( const XMLNode* compare ) const;
1009
1010 protected:
XMLText(XMLDocument * doc)1011 explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
~XMLText()1012 virtual ~XMLText() {}
1013
1014 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1015
1016 private:
1017 bool _isCData;
1018
1019 XMLText( const XMLText& ); // not supported
1020 XMLText& operator=( const XMLText& ); // not supported
1021 };
1022
1023
1024 /** An XML Comment. */
1025 class TINYXML2_LIB XMLComment : public XMLNode
1026 {
1027 friend class XMLDocument;
1028 public:
ToComment()1029 virtual XMLComment* ToComment() {
1030 return this;
1031 }
ToComment()1032 virtual const XMLComment* ToComment() const {
1033 return this;
1034 }
1035
1036 virtual bool Accept( XMLVisitor* visitor ) const;
1037
1038 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1039 virtual bool ShallowEqual( const XMLNode* compare ) const;
1040
1041 protected:
1042 explicit XMLComment( XMLDocument* doc );
1043 virtual ~XMLComment();
1044
1045 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
1046
1047 private:
1048 XMLComment( const XMLComment& ); // not supported
1049 XMLComment& operator=( const XMLComment& ); // not supported
1050 };
1051
1052
1053 /** In correct XML the declaration is the first entry in the file.
1054 @verbatim
1055 <?xml version="1.0" standalone="yes"?>
1056 @endverbatim
1057
1058 TinyXML-2 will happily read or write files without a declaration,
1059 however.
1060
1061 The text of the declaration isn't interpreted. It is parsed
1062 and written as a string.
1063 */
1064 class TINYXML2_LIB XMLDeclaration : public XMLNode
1065 {
1066 friend class XMLDocument;
1067 public:
ToDeclaration()1068 virtual XMLDeclaration* ToDeclaration() {
1069 return this;
1070 }
ToDeclaration()1071 virtual const XMLDeclaration* ToDeclaration() const {
1072 return this;
1073 }
1074
1075 virtual bool Accept( XMLVisitor* visitor ) const;
1076
1077 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1078 virtual bool ShallowEqual( const XMLNode* compare ) const;
1079
1080 protected:
1081 explicit XMLDeclaration( XMLDocument* doc );
1082 virtual ~XMLDeclaration();
1083
1084 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1085
1086 private:
1087 XMLDeclaration( const XMLDeclaration& ); // not supported
1088 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
1089 };
1090
1091
1092 /** Any tag that TinyXML-2 doesn't recognize is saved as an
1093 unknown. It is a tag of text, but should not be modified.
1094 It will be written back to the XML, unchanged, when the file
1095 is saved.
1096
1097 DTD tags get thrown into XMLUnknowns.
1098 */
1099 class TINYXML2_LIB XMLUnknown : public XMLNode
1100 {
1101 friend class XMLDocument;
1102 public:
ToUnknown()1103 virtual XMLUnknown* ToUnknown() {
1104 return this;
1105 }
ToUnknown()1106 virtual const XMLUnknown* ToUnknown() const {
1107 return this;
1108 }
1109
1110 virtual bool Accept( XMLVisitor* visitor ) const;
1111
1112 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1113 virtual bool ShallowEqual( const XMLNode* compare ) const;
1114
1115 protected:
1116 explicit XMLUnknown( XMLDocument* doc );
1117 virtual ~XMLUnknown();
1118
1119 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1120
1121 private:
1122 XMLUnknown( const XMLUnknown& ); // not supported
1123 XMLUnknown& operator=( const XMLUnknown& ); // not supported
1124 };
1125
1126
1127
1128 /** An attribute is a name-value pair. Elements have an arbitrary
1129 number of attributes, each with a unique name.
1130
1131 @note The attributes are not XMLNodes. You may only query the
1132 Next() attribute in a list.
1133 */
1134 class TINYXML2_LIB XMLAttribute
1135 {
1136 friend class XMLElement;
1137 public:
1138 /// The name of the attribute.
1139 const char* Name() const;
1140
1141 /// The value of the attribute.
1142 const char* Value() const;
1143
1144 /// Gets the line number the attribute is in, if the document was parsed from a file.
GetLineNum()1145 int GetLineNum() const { return _parseLineNum; }
1146
1147 /// The next attribute in the list.
Next()1148 const XMLAttribute* Next() const {
1149 return _next;
1150 }
1151
1152 /** IntValue interprets the attribute as an integer, and returns the value.
1153 If the value isn't an integer, 0 will be returned. There is no error checking;
1154 use QueryIntValue() if you need error checking.
1155 */
IntValue()1156 int IntValue() const {
1157 int i = 0;
1158 QueryIntValue(&i);
1159 return i;
1160 }
1161
Int64Value()1162 int64_t Int64Value() const {
1163 int64_t i = 0;
1164 QueryInt64Value(&i);
1165 return i;
1166 }
1167
Unsigned64Value()1168 uint64_t Unsigned64Value() const {
1169 uint64_t i = 0;
1170 QueryUnsigned64Value(&i);
1171 return i;
1172 }
1173
1174 /// Query as an unsigned integer. See IntValue()
UnsignedValue()1175 unsigned UnsignedValue() const {
1176 unsigned i=0;
1177 QueryUnsignedValue( &i );
1178 return i;
1179 }
1180 /// Query as a boolean. See IntValue()
BoolValue()1181 bool BoolValue() const {
1182 bool b=false;
1183 QueryBoolValue( &b );
1184 return b;
1185 }
1186 /// Query as a double. See IntValue()
DoubleValue()1187 double DoubleValue() const {
1188 double d=0;
1189 QueryDoubleValue( &d );
1190 return d;
1191 }
1192 /// Query as a float. See IntValue()
FloatValue()1193 float FloatValue() const {
1194 float f=0;
1195 QueryFloatValue( &f );
1196 return f;
1197 }
1198
1199 /** QueryIntValue interprets the attribute as an integer, and returns the value
1200 in the provided parameter. The function will return XML_SUCCESS on success,
1201 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1202 */
1203 XMLError QueryIntValue( int* value ) const;
1204 /// See QueryIntValue
1205 XMLError QueryUnsignedValue( unsigned int* value ) const;
1206 /// See QueryIntValue
1207 XMLError QueryInt64Value(int64_t* value) const;
1208 /// See QueryIntValue
1209 XMLError QueryUnsigned64Value(uint64_t* value) const;
1210 /// See QueryIntValue
1211 XMLError QueryBoolValue( bool* value ) const;
1212 /// See QueryIntValue
1213 XMLError QueryDoubleValue( double* value ) const;
1214 /// See QueryIntValue
1215 XMLError QueryFloatValue( float* value ) const;
1216
1217 /// Set the attribute to a string value.
1218 void SetAttribute( const char* value );
1219 /// Set the attribute to value.
1220 void SetAttribute( int value );
1221 /// Set the attribute to value.
1222 void SetAttribute( unsigned value );
1223 /// Set the attribute to value.
1224 void SetAttribute(int64_t value);
1225 /// Set the attribute to value.
1226 void SetAttribute(uint64_t value);
1227 /// Set the attribute to value.
1228 void SetAttribute( bool value );
1229 /// Set the attribute to value.
1230 void SetAttribute( double value );
1231 /// Set the attribute to value.
1232 void SetAttribute( float value );
1233
1234 private:
1235 enum { BUF_SIZE = 200 };
1236
XMLAttribute()1237 XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
~XMLAttribute()1238 virtual ~XMLAttribute() {}
1239
1240 XMLAttribute( const XMLAttribute& ); // not supported
1241 void operator=( const XMLAttribute& ); // not supported
1242 void SetName( const char* name );
1243
1244 char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
1245
1246 mutable StrPair _name;
1247 mutable StrPair _value;
1248 int _parseLineNum;
1249 XMLAttribute* _next;
1250 MemPool* _memPool;
1251 };
1252
1253
1254 /** The element is a container class. It has a value, the element name,
1255 and can contain other elements, text, comments, and unknowns.
1256 Elements also contain an arbitrary number of attributes.
1257 */
1258 class TINYXML2_LIB XMLElement : public XMLNode
1259 {
1260 friend class XMLDocument;
1261 public:
1262 /// Get the name of an element (which is the Value() of the node.)
Name()1263 const char* Name() const {
1264 return Value();
1265 }
1266 /// Set the name of the element.
1267 void SetName( const char* str, bool staticMem=false ) {
1268 SetValue( str, staticMem );
1269 }
1270
ToElement()1271 virtual XMLElement* ToElement() {
1272 return this;
1273 }
ToElement()1274 virtual const XMLElement* ToElement() const {
1275 return this;
1276 }
1277 virtual bool Accept( XMLVisitor* visitor ) const;
1278
1279 /** Given an attribute name, Attribute() returns the value
1280 for the attribute of that name, or null if none
1281 exists. For example:
1282
1283 @verbatim
1284 const char* value = ele->Attribute( "foo" );
1285 @endverbatim
1286
1287 The 'value' parameter is normally null. However, if specified,
1288 the attribute will only be returned if the 'name' and 'value'
1289 match. This allow you to write code:
1290
1291 @verbatim
1292 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1293 @endverbatim
1294
1295 rather than:
1296 @verbatim
1297 if ( ele->Attribute( "foo" ) ) {
1298 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1299 }
1300 @endverbatim
1301 */
1302 const char* Attribute( const char* name, const char* value=0 ) const;
1303
1304 /** Given an attribute name, IntAttribute() returns the value
1305 of the attribute interpreted as an integer. The default
1306 value will be returned if the attribute isn't present,
1307 or if there is an error. (For a method with error
1308 checking, see QueryIntAttribute()).
1309 */
1310 int IntAttribute(const char* name, int defaultValue = 0) const;
1311 /// See IntAttribute()
1312 unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
1313 /// See IntAttribute()
1314 int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
1315 /// See IntAttribute()
1316 uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const;
1317 /// See IntAttribute()
1318 bool BoolAttribute(const char* name, bool defaultValue = false) const;
1319 /// See IntAttribute()
1320 double DoubleAttribute(const char* name, double defaultValue = 0) const;
1321 /// See IntAttribute()
1322 float FloatAttribute(const char* name, float defaultValue = 0) const;
1323
1324 /** Given an attribute name, QueryIntAttribute() returns
1325 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1326 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1327 doesn't exist. If successful, the result of the conversion
1328 will be written to 'value'. If not successful, nothing will
1329 be written to 'value'. This allows you to provide default
1330 value:
1331
1332 @verbatim
1333 int value = 10;
1334 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1335 @endverbatim
1336 */
QueryIntAttribute(const char * name,int * value)1337 XMLError QueryIntAttribute( const char* name, int* value ) const {
1338 const XMLAttribute* a = FindAttribute( name );
1339 if ( !a ) {
1340 return XML_NO_ATTRIBUTE;
1341 }
1342 return a->QueryIntValue( value );
1343 }
1344
1345 /// See QueryIntAttribute()
QueryUnsignedAttribute(const char * name,unsigned int * value)1346 XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
1347 const XMLAttribute* a = FindAttribute( name );
1348 if ( !a ) {
1349 return XML_NO_ATTRIBUTE;
1350 }
1351 return a->QueryUnsignedValue( value );
1352 }
1353
1354 /// See QueryIntAttribute()
QueryInt64Attribute(const char * name,int64_t * value)1355 XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
1356 const XMLAttribute* a = FindAttribute(name);
1357 if (!a) {
1358 return XML_NO_ATTRIBUTE;
1359 }
1360 return a->QueryInt64Value(value);
1361 }
1362
1363 /// See QueryIntAttribute()
QueryUnsigned64Attribute(const char * name,uint64_t * value)1364 XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const {
1365 const XMLAttribute* a = FindAttribute(name);
1366 if(!a) {
1367 return XML_NO_ATTRIBUTE;
1368 }
1369 return a->QueryUnsigned64Value(value);
1370 }
1371
1372 /// See QueryIntAttribute()
QueryBoolAttribute(const char * name,bool * value)1373 XMLError QueryBoolAttribute( const char* name, bool* value ) const {
1374 const XMLAttribute* a = FindAttribute( name );
1375 if ( !a ) {
1376 return XML_NO_ATTRIBUTE;
1377 }
1378 return a->QueryBoolValue( value );
1379 }
1380 /// See QueryIntAttribute()
QueryDoubleAttribute(const char * name,double * value)1381 XMLError QueryDoubleAttribute( const char* name, double* value ) const {
1382 const XMLAttribute* a = FindAttribute( name );
1383 if ( !a ) {
1384 return XML_NO_ATTRIBUTE;
1385 }
1386 return a->QueryDoubleValue( value );
1387 }
1388 /// See QueryIntAttribute()
QueryFloatAttribute(const char * name,float * value)1389 XMLError QueryFloatAttribute( const char* name, float* value ) const {
1390 const XMLAttribute* a = FindAttribute( name );
1391 if ( !a ) {
1392 return XML_NO_ATTRIBUTE;
1393 }
1394 return a->QueryFloatValue( value );
1395 }
1396
1397 /// See QueryIntAttribute()
QueryStringAttribute(const char * name,const char ** value)1398 XMLError QueryStringAttribute(const char* name, const char** value) const {
1399 const XMLAttribute* a = FindAttribute(name);
1400 if (!a) {
1401 return XML_NO_ATTRIBUTE;
1402 }
1403 *value = a->Value();
1404 return XML_SUCCESS;
1405 }
1406
1407
1408
1409 /** Given an attribute name, QueryAttribute() returns
1410 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1411 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1412 doesn't exist. It is overloaded for the primitive types,
1413 and is a generally more convenient replacement of
1414 QueryIntAttribute() and related functions.
1415
1416 If successful, the result of the conversion
1417 will be written to 'value'. If not successful, nothing will
1418 be written to 'value'. This allows you to provide default
1419 value:
1420
1421 @verbatim
1422 int value = 10;
1423 QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1424 @endverbatim
1425 */
QueryAttribute(const char * name,int * value)1426 XMLError QueryAttribute( const char* name, int* value ) const {
1427 return QueryIntAttribute( name, value );
1428 }
1429
QueryAttribute(const char * name,unsigned int * value)1430 XMLError QueryAttribute( const char* name, unsigned int* value ) const {
1431 return QueryUnsignedAttribute( name, value );
1432 }
1433
QueryAttribute(const char * name,int64_t * value)1434 XMLError QueryAttribute(const char* name, int64_t* value) const {
1435 return QueryInt64Attribute(name, value);
1436 }
1437
QueryAttribute(const char * name,uint64_t * value)1438 XMLError QueryAttribute(const char* name, uint64_t* value) const {
1439 return QueryUnsigned64Attribute(name, value);
1440 }
1441
QueryAttribute(const char * name,bool * value)1442 XMLError QueryAttribute( const char* name, bool* value ) const {
1443 return QueryBoolAttribute( name, value );
1444 }
1445
QueryAttribute(const char * name,double * value)1446 XMLError QueryAttribute( const char* name, double* value ) const {
1447 return QueryDoubleAttribute( name, value );
1448 }
1449
QueryAttribute(const char * name,float * value)1450 XMLError QueryAttribute( const char* name, float* value ) const {
1451 return QueryFloatAttribute( name, value );
1452 }
1453
1454 /// Sets the named attribute to value.
SetAttribute(const char * name,const char * value)1455 void SetAttribute( const char* name, const char* value ) {
1456 XMLAttribute* a = FindOrCreateAttribute( name );
1457 a->SetAttribute( value );
1458 }
1459 /// Sets the named attribute to value.
SetAttribute(const char * name,int value)1460 void SetAttribute( const char* name, int value ) {
1461 XMLAttribute* a = FindOrCreateAttribute( name );
1462 a->SetAttribute( value );
1463 }
1464 /// Sets the named attribute to value.
SetAttribute(const char * name,unsigned value)1465 void SetAttribute( const char* name, unsigned value ) {
1466 XMLAttribute* a = FindOrCreateAttribute( name );
1467 a->SetAttribute( value );
1468 }
1469
1470 /// Sets the named attribute to value.
SetAttribute(const char * name,int64_t value)1471 void SetAttribute(const char* name, int64_t value) {
1472 XMLAttribute* a = FindOrCreateAttribute(name);
1473 a->SetAttribute(value);
1474 }
1475
1476 /// Sets the named attribute to value.
SetAttribute(const char * name,uint64_t value)1477 void SetAttribute(const char* name, uint64_t value) {
1478 XMLAttribute* a = FindOrCreateAttribute(name);
1479 a->SetAttribute(value);
1480 }
1481
1482 /// Sets the named attribute to value.
SetAttribute(const char * name,bool value)1483 void SetAttribute( const char* name, bool value ) {
1484 XMLAttribute* a = FindOrCreateAttribute( name );
1485 a->SetAttribute( value );
1486 }
1487 /// Sets the named attribute to value.
SetAttribute(const char * name,double value)1488 void SetAttribute( const char* name, double value ) {
1489 XMLAttribute* a = FindOrCreateAttribute( name );
1490 a->SetAttribute( value );
1491 }
1492 /// Sets the named attribute to value.
SetAttribute(const char * name,float value)1493 void SetAttribute( const char* name, float value ) {
1494 XMLAttribute* a = FindOrCreateAttribute( name );
1495 a->SetAttribute( value );
1496 }
1497
1498 /**
1499 Delete an attribute.
1500 */
1501 void DeleteAttribute( const char* name );
1502
1503 /// Return the first attribute in the list.
FirstAttribute()1504 const XMLAttribute* FirstAttribute() const {
1505 return _rootAttribute;
1506 }
1507 /// Query a specific attribute in the list.
1508 const XMLAttribute* FindAttribute( const char* name ) const;
1509
1510 /** Convenience function for easy access to the text inside an element. Although easy
1511 and concise, GetText() is limited compared to getting the XMLText child
1512 and accessing it directly.
1513
1514 If the first child of 'this' is a XMLText, the GetText()
1515 returns the character string of the Text node, else null is returned.
1516
1517 This is a convenient method for getting the text of simple contained text:
1518 @verbatim
1519 <foo>This is text</foo>
1520 const char* str = fooElement->GetText();
1521 @endverbatim
1522
1523 'str' will be a pointer to "This is text".
1524
1525 Note that this function can be misleading. If the element foo was created from
1526 this XML:
1527 @verbatim
1528 <foo><b>This is text</b></foo>
1529 @endverbatim
1530
1531 then the value of str would be null. The first child node isn't a text node, it is
1532 another element. From this XML:
1533 @verbatim
1534 <foo>This is <b>text</b></foo>
1535 @endverbatim
1536 GetText() will return "This is ".
1537 */
1538 const char* GetText() const;
1539
1540 /** Convenience function for easy access to the text inside an element. Although easy
1541 and concise, SetText() is limited compared to creating an XMLText child
1542 and mutating it directly.
1543
1544 If the first child of 'this' is a XMLText, SetText() sets its value to
1545 the given string, otherwise it will create a first child that is an XMLText.
1546
1547 This is a convenient method for setting the text of simple contained text:
1548 @verbatim
1549 <foo>This is text</foo>
1550 fooElement->SetText( "Hullaballoo!" );
1551 <foo>Hullaballoo!</foo>
1552 @endverbatim
1553
1554 Note that this function can be misleading. If the element foo was created from
1555 this XML:
1556 @verbatim
1557 <foo><b>This is text</b></foo>
1558 @endverbatim
1559
1560 then it will not change "This is text", but rather prefix it with a text element:
1561 @verbatim
1562 <foo>Hullaballoo!<b>This is text</b></foo>
1563 @endverbatim
1564
1565 For this XML:
1566 @verbatim
1567 <foo />
1568 @endverbatim
1569 SetText() will generate
1570 @verbatim
1571 <foo>Hullaballoo!</foo>
1572 @endverbatim
1573 */
1574 void SetText( const char* inText );
1575 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1576 void SetText( int value );
1577 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1578 void SetText( unsigned value );
1579 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1580 void SetText(int64_t value);
1581 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1582 void SetText(uint64_t value);
1583 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1584 void SetText( bool value );
1585 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1586 void SetText( double value );
1587 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1588 void SetText( float value );
1589
1590 /**
1591 Convenience method to query the value of a child text node. This is probably best
1592 shown by example. Given you have a document is this form:
1593 @verbatim
1594 <point>
1595 <x>1</x>
1596 <y>1.4</y>
1597 </point>
1598 @endverbatim
1599
1600 The QueryIntText() and similar functions provide a safe and easier way to get to the
1601 "value" of x and y.
1602
1603 @verbatim
1604 int x = 0;
1605 float y = 0; // types of x and y are contrived for example
1606 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1607 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1608 xElement->QueryIntText( &x );
1609 yElement->QueryFloatText( &y );
1610 @endverbatim
1611
1612 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1613 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
1614
1615 */
1616 XMLError QueryIntText( int* ival ) const;
1617 /// See QueryIntText()
1618 XMLError QueryUnsignedText( unsigned* uval ) const;
1619 /// See QueryIntText()
1620 XMLError QueryInt64Text(int64_t* uval) const;
1621 /// See QueryIntText()
1622 XMLError QueryUnsigned64Text(uint64_t* uval) const;
1623 /// See QueryIntText()
1624 XMLError QueryBoolText( bool* bval ) const;
1625 /// See QueryIntText()
1626 XMLError QueryDoubleText( double* dval ) const;
1627 /// See QueryIntText()
1628 XMLError QueryFloatText( float* fval ) const;
1629
1630 int IntText(int defaultValue = 0) const;
1631
1632 /// See QueryIntText()
1633 unsigned UnsignedText(unsigned defaultValue = 0) const;
1634 /// See QueryIntText()
1635 int64_t Int64Text(int64_t defaultValue = 0) const;
1636 /// See QueryIntText()
1637 uint64_t Unsigned64Text(uint64_t defaultValue = 0) const;
1638 /// See QueryIntText()
1639 bool BoolText(bool defaultValue = false) const;
1640 /// See QueryIntText()
1641 double DoubleText(double defaultValue = 0) const;
1642 /// See QueryIntText()
1643 float FloatText(float defaultValue = 0) const;
1644
1645 /**
1646 Convenience method to create a new XMLElement and add it as last (right)
1647 child of this node. Returns the created and inserted element.
1648 */
1649 XMLElement* InsertNewChildElement(const char* name);
1650 /// See InsertNewChildElement()
1651 XMLComment* InsertNewComment(const char* comment);
1652 /// See InsertNewChildElement()
1653 XMLText* InsertNewText(const char* text);
1654 /// See InsertNewChildElement()
1655 XMLDeclaration* InsertNewDeclaration(const char* text);
1656 /// See InsertNewChildElement()
1657 XMLUnknown* InsertNewUnknown(const char* text);
1658
1659
1660 // internal:
1661 enum ElementClosingType {
1662 OPEN, // <foo>
1663 CLOSED, // <foo/>
1664 CLOSING // </foo>
1665 };
ClosingType()1666 ElementClosingType ClosingType() const {
1667 return _closingType;
1668 }
1669 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1670 virtual bool ShallowEqual( const XMLNode* compare ) const;
1671
1672 protected:
1673 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
1674
1675 private:
1676 XMLElement( XMLDocument* doc );
1677 virtual ~XMLElement();
1678 XMLElement( const XMLElement& ); // not supported
1679 void operator=( const XMLElement& ); // not supported
1680
1681 XMLAttribute* FindOrCreateAttribute( const char* name );
1682 char* ParseAttributes( char* p, int* curLineNumPtr );
1683 static void DeleteAttribute( XMLAttribute* attribute );
1684 XMLAttribute* CreateAttribute();
1685
1686 enum { BUF_SIZE = 200 };
1687 ElementClosingType _closingType;
1688 // The attribute list is ordered; there is no 'lastAttribute'
1689 // because the list needs to be scanned for dupes before adding
1690 // a new attribute.
1691 XMLAttribute* _rootAttribute;
1692 };
1693
1694
1695 enum Whitespace {
1696 PRESERVE_WHITESPACE,
1697 COLLAPSE_WHITESPACE
1698 };
1699
1700
1701 /** A Document binds together all the functionality.
1702 It can be saved, loaded, and printed to the screen.
1703 All Nodes are connected and allocated to a Document.
1704 If the Document is deleted, all its Nodes are also deleted.
1705 */
1706 class TINYXML2_LIB XMLDocument : public XMLNode
1707 {
1708 friend class XMLElement;
1709 // Gives access to SetError and Push/PopDepth, but over-access for everything else.
1710 // Wishing C++ had "internal" scope.
1711 friend class XMLNode;
1712 friend class XMLText;
1713 friend class XMLComment;
1714 friend class XMLDeclaration;
1715 friend class XMLUnknown;
1716 public:
1717 /// constructor
1718 XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
1719 ~XMLDocument();
1720
ToDocument()1721 virtual XMLDocument* ToDocument() {
1722 TIXMLASSERT( this == _document );
1723 return this;
1724 }
ToDocument()1725 virtual const XMLDocument* ToDocument() const {
1726 TIXMLASSERT( this == _document );
1727 return this;
1728 }
1729
1730 /**
1731 Parse an XML file from a character string.
1732 Returns XML_SUCCESS (0) on success, or
1733 an errorID.
1734
1735 You may optionally pass in the 'nBytes', which is
1736 the number of bytes which will be parsed. If not
1737 specified, TinyXML-2 will assume 'xml' points to a
1738 null terminated string.
1739 */
1740 XMLError Parse( const char* xml, size_t nBytes=static_cast<size_t>(-1) );
1741
1742 /**
1743 Load an XML file from disk.
1744 Returns XML_SUCCESS (0) on success, or
1745 an errorID.
1746 */
1747 XMLError LoadFile( const char* filename );
1748
1749 /**
1750 Load an XML file from disk. You are responsible
1751 for providing and closing the FILE*.
1752
1753 NOTE: The file should be opened as binary ("rb")
1754 not text in order for TinyXML-2 to correctly
1755 do newline normalization.
1756
1757 Returns XML_SUCCESS (0) on success, or
1758 an errorID.
1759 */
1760 XMLError LoadFile( FILE* );
1761
1762 /**
1763 Save the XML file to disk.
1764 Returns XML_SUCCESS (0) on success, or
1765 an errorID.
1766 */
1767 XMLError SaveFile( const char* filename, bool compact = false );
1768
1769 /**
1770 Save the XML file to disk. You are responsible
1771 for providing and closing the FILE*.
1772
1773 Returns XML_SUCCESS (0) on success, or
1774 an errorID.
1775 */
1776 XMLError SaveFile( FILE* fp, bool compact = false );
1777
ProcessEntities()1778 bool ProcessEntities() const {
1779 return _processEntities;
1780 }
WhitespaceMode()1781 Whitespace WhitespaceMode() const {
1782 return _whitespaceMode;
1783 }
1784
1785 /**
1786 Returns true if this document has a leading Byte Order Mark of UTF8.
1787 */
HasBOM()1788 bool HasBOM() const {
1789 return _writeBOM;
1790 }
1791 /** Sets whether to write the BOM when writing the file.
1792 */
SetBOM(bool useBOM)1793 void SetBOM( bool useBOM ) {
1794 _writeBOM = useBOM;
1795 }
1796
1797 /** Return the root element of DOM. Equivalent to FirstChildElement().
1798 To get the first node, use FirstChild().
1799 */
RootElement()1800 XMLElement* RootElement() {
1801 return FirstChildElement();
1802 }
RootElement()1803 const XMLElement* RootElement() const {
1804 return FirstChildElement();
1805 }
1806
1807 /** Print the Document. If the Printer is not provided, it will
1808 print to stdout. If you provide Printer, this can print to a file:
1809 @verbatim
1810 XMLPrinter printer( fp );
1811 doc.Print( &printer );
1812 @endverbatim
1813
1814 Or you can use a printer to print to memory:
1815 @verbatim
1816 XMLPrinter printer;
1817 doc.Print( &printer );
1818 // printer.CStr() has a const char* to the XML
1819 @endverbatim
1820 */
1821 void Print( XMLPrinter* streamer=0 ) const;
1822 virtual bool Accept( XMLVisitor* visitor ) const;
1823
1824 /**
1825 Create a new Element associated with
1826 this Document. The memory for the Element
1827 is managed by the Document.
1828 */
1829 XMLElement* NewElement( const char* name );
1830 /**
1831 Create a new Comment associated with
1832 this Document. The memory for the Comment
1833 is managed by the Document.
1834 */
1835 XMLComment* NewComment( const char* comment );
1836 /**
1837 Create a new Text associated with
1838 this Document. The memory for the Text
1839 is managed by the Document.
1840 */
1841 XMLText* NewText( const char* text );
1842 /**
1843 Create a new Declaration associated with
1844 this Document. The memory for the object
1845 is managed by the Document.
1846
1847 If the 'text' param is null, the standard
1848 declaration is used.:
1849 @verbatim
1850 <?xml version="1.0" encoding="UTF-8"?>
1851 @endverbatim
1852 */
1853 XMLDeclaration* NewDeclaration( const char* text=0 );
1854 /**
1855 Create a new Unknown associated with
1856 this Document. The memory for the object
1857 is managed by the Document.
1858 */
1859 XMLUnknown* NewUnknown( const char* text );
1860
1861 /**
1862 Delete a node associated with this document.
1863 It will be unlinked from the DOM.
1864 */
1865 void DeleteNode( XMLNode* node );
1866
ClearError()1867 void ClearError() {
1868 SetError(XML_SUCCESS, 0, 0);
1869 }
1870
1871 /// Return true if there was an error parsing the document.
Error()1872 bool Error() const {
1873 return _errorID != XML_SUCCESS;
1874 }
1875 /// Return the errorID.
ErrorID()1876 XMLError ErrorID() const {
1877 return _errorID;
1878 }
1879 const char* ErrorName() const;
1880 static const char* ErrorIDToName(XMLError errorID);
1881
1882 /** Returns a "long form" error description. A hopefully helpful
1883 diagnostic with location, line number, and/or additional info.
1884 */
1885 const char* ErrorStr() const;
1886
1887 /// A (trivial) utility function that prints the ErrorStr() to stdout.
1888 void PrintError() const;
1889
1890 /// Return the line where the error occurred, or zero if unknown.
ErrorLineNum()1891 int ErrorLineNum() const
1892 {
1893 return _errorLineNum;
1894 }
1895
1896 /// Clear the document, resetting it to the initial state.
1897 void Clear();
1898
1899 /**
1900 Copies this document to a target document.
1901 The target will be completely cleared before the copy.
1902 If you want to copy a sub-tree, see XMLNode::DeepClone().
1903
1904 NOTE: that the 'target' must be non-null.
1905 */
1906 void DeepCopy(XMLDocument* target) const;
1907
1908 // internal
1909 char* Identify( char* p, XMLNode** node );
1910
1911 // internal
1912 void MarkInUse(const XMLNode* const);
1913
ShallowClone(XMLDocument *)1914 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
1915 return 0;
1916 }
ShallowEqual(const XMLNode *)1917 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
1918 return false;
1919 }
1920
1921 private:
1922 XMLDocument( const XMLDocument& ); // not supported
1923 void operator=( const XMLDocument& ); // not supported
1924
1925 bool _writeBOM;
1926 bool _processEntities;
1927 XMLError _errorID;
1928 Whitespace _whitespaceMode;
1929 mutable StrPair _errorStr;
1930 int _errorLineNum;
1931 char* _charBuffer;
1932 int _parseCurLineNum;
1933 int _parsingDepth;
1934 // Memory tracking does add some overhead.
1935 // However, the code assumes that you don't
1936 // have a bunch of unlinked nodes around.
1937 // Therefore it takes less memory to track
1938 // in the document vs. a linked list in the XMLNode,
1939 // and the performance is the same.
1940 DynArray<XMLNode*, 10> _unlinked;
1941
1942 MemPoolT< sizeof(XMLElement) > _elementPool;
1943 MemPoolT< sizeof(XMLAttribute) > _attributePool;
1944 MemPoolT< sizeof(XMLText) > _textPool;
1945 MemPoolT< sizeof(XMLComment) > _commentPool;
1946
1947 static const char* _errorNames[XML_ERROR_COUNT];
1948
1949 void Parse();
1950
1951 void SetError( XMLError error, int lineNum, const char* format, ... );
1952
1953 // Something of an obvious security hole, once it was discovered.
1954 // Either an ill-formed XML or an excessively deep one can overflow
1955 // the stack. Track stack depth, and error out if needed.
1956 class DepthTracker {
1957 public:
DepthTracker(XMLDocument * document)1958 explicit DepthTracker(XMLDocument * document) {
1959 this->_document = document;
1960 document->PushDepth();
1961 }
~DepthTracker()1962 ~DepthTracker() {
1963 _document->PopDepth();
1964 }
1965 private:
1966 XMLDocument * _document;
1967 };
1968 void PushDepth();
1969 void PopDepth();
1970
1971 template<class NodeType, int PoolElementSize>
1972 NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
1973 };
1974
1975 template<class NodeType, int PoolElementSize>
CreateUnlinkedNode(MemPoolT<PoolElementSize> & pool)1976 inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
1977 {
1978 TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
1979 TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
1980 NodeType* returnNode = new (pool.Alloc()) NodeType( this );
1981 TIXMLASSERT( returnNode );
1982 returnNode->_memPool = &pool;
1983
1984 _unlinked.Push(returnNode);
1985 return returnNode;
1986 }
1987
1988 /**
1989 A XMLHandle is a class that wraps a node pointer with null checks; this is
1990 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
1991 DOM structure. It is a separate utility class.
1992
1993 Take an example:
1994 @verbatim
1995 <Document>
1996 <Element attributeA = "valueA">
1997 <Child attributeB = "value1" />
1998 <Child attributeB = "value2" />
1999 </Element>
2000 </Document>
2001 @endverbatim
2002
2003 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
2004 easy to write a *lot* of code that looks like:
2005
2006 @verbatim
2007 XMLElement* root = document.FirstChildElement( "Document" );
2008 if ( root )
2009 {
2010 XMLElement* element = root->FirstChildElement( "Element" );
2011 if ( element )
2012 {
2013 XMLElement* child = element->FirstChildElement( "Child" );
2014 if ( child )
2015 {
2016 XMLElement* child2 = child->NextSiblingElement( "Child" );
2017 if ( child2 )
2018 {
2019 // Finally do something useful.
2020 @endverbatim
2021
2022 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
2023 of such code. A XMLHandle checks for null pointers so it is perfectly safe
2024 and correct to use:
2025
2026 @verbatim
2027 XMLHandle docHandle( &document );
2028 XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
2029 if ( child2 )
2030 {
2031 // do something useful
2032 @endverbatim
2033
2034 Which is MUCH more concise and useful.
2035
2036 It is also safe to copy handles - internally they are nothing more than node pointers.
2037 @verbatim
2038 XMLHandle handleCopy = handle;
2039 @endverbatim
2040
2041 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
2042 */
2043 class TINYXML2_LIB XMLHandle
2044 {
2045 public:
2046 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
XMLHandle(XMLNode * node)2047 explicit XMLHandle( XMLNode* node ) : _node( node ) {
2048 }
2049 /// Create a handle from a node.
XMLHandle(XMLNode & node)2050 explicit XMLHandle( XMLNode& node ) : _node( &node ) {
2051 }
2052 /// Copy constructor
XMLHandle(const XMLHandle & ref)2053 XMLHandle( const XMLHandle& ref ) : _node( ref._node ) {
2054 }
2055 /// Assignment
2056 XMLHandle& operator=( const XMLHandle& ref ) {
2057 _node = ref._node;
2058 return *this;
2059 }
2060
2061 /// Get the first child of this handle.
FirstChild()2062 XMLHandle FirstChild() {
2063 return XMLHandle( _node ? _node->FirstChild() : 0 );
2064 }
2065 /// Get the first child element of this handle.
2066 XMLHandle FirstChildElement( const char* name = 0 ) {
2067 return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
2068 }
2069 /// Get the last child of this handle.
LastChild()2070 XMLHandle LastChild() {
2071 return XMLHandle( _node ? _node->LastChild() : 0 );
2072 }
2073 /// Get the last child element of this handle.
2074 XMLHandle LastChildElement( const char* name = 0 ) {
2075 return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
2076 }
2077 /// Get the previous sibling of this handle.
PreviousSibling()2078 XMLHandle PreviousSibling() {
2079 return XMLHandle( _node ? _node->PreviousSibling() : 0 );
2080 }
2081 /// Get the previous sibling element of this handle.
2082 XMLHandle PreviousSiblingElement( const char* name = 0 ) {
2083 return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
2084 }
2085 /// Get the next sibling of this handle.
NextSibling()2086 XMLHandle NextSibling() {
2087 return XMLHandle( _node ? _node->NextSibling() : 0 );
2088 }
2089 /// Get the next sibling element of this handle.
2090 XMLHandle NextSiblingElement( const char* name = 0 ) {
2091 return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
2092 }
2093
2094 /// Safe cast to XMLNode. This can return null.
ToNode()2095 XMLNode* ToNode() {
2096 return _node;
2097 }
2098 /// Safe cast to XMLElement. This can return null.
ToElement()2099 XMLElement* ToElement() {
2100 return ( _node ? _node->ToElement() : 0 );
2101 }
2102 /// Safe cast to XMLText. This can return null.
ToText()2103 XMLText* ToText() {
2104 return ( _node ? _node->ToText() : 0 );
2105 }
2106 /// Safe cast to XMLUnknown. This can return null.
ToUnknown()2107 XMLUnknown* ToUnknown() {
2108 return ( _node ? _node->ToUnknown() : 0 );
2109 }
2110 /// Safe cast to XMLDeclaration. This can return null.
ToDeclaration()2111 XMLDeclaration* ToDeclaration() {
2112 return ( _node ? _node->ToDeclaration() : 0 );
2113 }
2114
2115 private:
2116 XMLNode* _node;
2117 };
2118
2119
2120 /**
2121 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
2122 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
2123 */
2124 class TINYXML2_LIB XMLConstHandle
2125 {
2126 public:
XMLConstHandle(const XMLNode * node)2127 explicit XMLConstHandle( const XMLNode* node ) : _node( node ) {
2128 }
XMLConstHandle(const XMLNode & node)2129 explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) {
2130 }
XMLConstHandle(const XMLConstHandle & ref)2131 XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) {
2132 }
2133
2134 XMLConstHandle& operator=( const XMLConstHandle& ref ) {
2135 _node = ref._node;
2136 return *this;
2137 }
2138
FirstChild()2139 const XMLConstHandle FirstChild() const {
2140 return XMLConstHandle( _node ? _node->FirstChild() : 0 );
2141 }
2142 const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
2143 return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
2144 }
LastChild()2145 const XMLConstHandle LastChild() const {
2146 return XMLConstHandle( _node ? _node->LastChild() : 0 );
2147 }
2148 const XMLConstHandle LastChildElement( const char* name = 0 ) const {
2149 return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
2150 }
PreviousSibling()2151 const XMLConstHandle PreviousSibling() const {
2152 return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
2153 }
2154 const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
2155 return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
2156 }
NextSibling()2157 const XMLConstHandle NextSibling() const {
2158 return XMLConstHandle( _node ? _node->NextSibling() : 0 );
2159 }
2160 const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
2161 return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
2162 }
2163
2164
ToNode()2165 const XMLNode* ToNode() const {
2166 return _node;
2167 }
ToElement()2168 const XMLElement* ToElement() const {
2169 return ( _node ? _node->ToElement() : 0 );
2170 }
ToText()2171 const XMLText* ToText() const {
2172 return ( _node ? _node->ToText() : 0 );
2173 }
ToUnknown()2174 const XMLUnknown* ToUnknown() const {
2175 return ( _node ? _node->ToUnknown() : 0 );
2176 }
ToDeclaration()2177 const XMLDeclaration* ToDeclaration() const {
2178 return ( _node ? _node->ToDeclaration() : 0 );
2179 }
2180
2181 private:
2182 const XMLNode* _node;
2183 };
2184
2185
2186 /**
2187 Printing functionality. The XMLPrinter gives you more
2188 options than the XMLDocument::Print() method.
2189
2190 It can:
2191 -# Print to memory.
2192 -# Print to a file you provide.
2193 -# Print XML without a XMLDocument.
2194
2195 Print to Memory
2196
2197 @verbatim
2198 XMLPrinter printer;
2199 doc.Print( &printer );
2200 SomeFunction( printer.CStr() );
2201 @endverbatim
2202
2203 Print to a File
2204
2205 You provide the file pointer.
2206 @verbatim
2207 XMLPrinter printer( fp );
2208 doc.Print( &printer );
2209 @endverbatim
2210
2211 Print without a XMLDocument
2212
2213 When loading, an XML parser is very useful. However, sometimes
2214 when saving, it just gets in the way. The code is often set up
2215 for streaming, and constructing the DOM is just overhead.
2216
2217 The Printer supports the streaming case. The following code
2218 prints out a trivially simple XML file without ever creating
2219 an XML document.
2220
2221 @verbatim
2222 XMLPrinter printer( fp );
2223 printer.OpenElement( "foo" );
2224 printer.PushAttribute( "foo", "bar" );
2225 printer.CloseElement();
2226 @endverbatim
2227 */
2228 class TINYXML2_LIB XMLPrinter : public XMLVisitor
2229 {
2230 public:
2231 /** Construct the printer. If the FILE* is specified,
2232 this will print to the FILE. Else it will print
2233 to memory, and the result is available in CStr().
2234 If 'compact' is set to true, then output is created
2235 with only required whitespace and newlines.
2236 */
2237 XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
~XMLPrinter()2238 virtual ~XMLPrinter() {}
2239
2240 /** If streaming, write the BOM and declaration. */
2241 void PushHeader( bool writeBOM, bool writeDeclaration );
2242 /** If streaming, start writing an element.
2243 The element must be closed with CloseElement()
2244 */
2245 void OpenElement( const char* name, bool compactMode=false );
2246 /// If streaming, add an attribute to an open element.
2247 void PushAttribute( const char* name, const char* value );
2248 void PushAttribute( const char* name, int value );
2249 void PushAttribute( const char* name, unsigned value );
2250 void PushAttribute( const char* name, int64_t value );
2251 void PushAttribute( const char* name, uint64_t value );
2252 void PushAttribute( const char* name, bool value );
2253 void PushAttribute( const char* name, double value );
2254 /// If streaming, close the Element.
2255 virtual void CloseElement( bool compactMode=false );
2256
2257 /// Add a text node.
2258 void PushText( const char* text, bool cdata=false );
2259 /// Add a text node from an integer.
2260 void PushText( int value );
2261 /// Add a text node from an unsigned.
2262 void PushText( unsigned value );
2263 /// Add a text node from a signed 64bit integer.
2264 void PushText( int64_t value );
2265 /// Add a text node from an unsigned 64bit integer.
2266 void PushText( uint64_t value );
2267 /// Add a text node from a bool.
2268 void PushText( bool value );
2269 /// Add a text node from a float.
2270 void PushText( float value );
2271 /// Add a text node from a double.
2272 void PushText( double value );
2273
2274 /// Add a comment
2275 void PushComment( const char* comment );
2276
2277 void PushDeclaration( const char* value );
2278 void PushUnknown( const char* value );
2279
2280 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
VisitExit(const XMLDocument &)2281 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
2282 return true;
2283 }
2284
2285 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
2286 virtual bool VisitExit( const XMLElement& element );
2287
2288 virtual bool Visit( const XMLText& text );
2289 virtual bool Visit( const XMLComment& comment );
2290 virtual bool Visit( const XMLDeclaration& declaration );
2291 virtual bool Visit( const XMLUnknown& unknown );
2292
2293 /**
2294 If in print to memory mode, return a pointer to
2295 the XML file in memory.
2296 */
CStr()2297 const char* CStr() const {
2298 return _buffer.Mem();
2299 }
2300 /**
2301 If in print to memory mode, return the size
2302 of the XML file in memory. (Note the size returned
2303 includes the terminating null.)
2304 */
CStrSize()2305 int CStrSize() const {
2306 return _buffer.Size();
2307 }
2308 /**
2309 If in print to memory mode, reset the buffer to the
2310 beginning.
2311 */
2312 void ClearBuffer( bool resetToFirstElement = true ) {
2313 _buffer.Clear();
2314 _buffer.Push(0);
2315 _firstElement = resetToFirstElement;
2316 }
2317
2318 protected:
CompactMode(const XMLElement &)2319 virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
2320
2321 /** Prints out the space before an element. You may override to change
2322 the space and tabs used. A PrintSpace() override should call Print().
2323 */
2324 virtual void PrintSpace( int depth );
2325 void Print( const char* format, ... );
2326 void Write( const char* data, size_t size );
Write(const char * data)2327 inline void Write( const char* data ) { Write( data, strlen( data ) ); }
2328 void Putc( char ch );
2329
2330 void SealElementIfJustOpened();
2331 bool _elementJustOpened;
2332 DynArray< const char*, 10 > _stack;
2333
2334 private:
2335 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
2336
2337 bool _firstElement;
2338 FILE* _fp;
2339 int _depth;
2340 int _textDepth;
2341 bool _processEntities;
2342 bool _compactMode;
2343
2344 enum {
2345 ENTITY_RANGE = 64,
2346 BUF_SIZE = 200
2347 };
2348 bool _entityFlag[ENTITY_RANGE];
2349 bool _restrictedEntityFlag[ENTITY_RANGE];
2350
2351 DynArray< char, 20 > _buffer;
2352
2353 // Prohibit cloning, intentionally not implemented
2354 XMLPrinter( const XMLPrinter& );
2355 XMLPrinter& operator=( const XMLPrinter& );
2356 };
2357
2358
2359 } // tinyxml2
2360
2361 #if defined(_MSC_VER)
2362 # pragma warning(pop)
2363 #endif
2364
2365 #endif // TINYXML2_INCLUDED
2366