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