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