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