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