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