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