blob: d0d0a83b1e480f5fce16f0b27654c537b5f738b5 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
Lee Thomason50f97b22012-02-11 16:33:40 -080024#ifndef TINYXML_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025#define TINYXML2_INCLUDED
26
Lee Thomason2c85a712012-01-31 08:24:24 -080027
U-Lama\Lee4cee6112011-12-31 14:58:18 -080028#include <limits.h>
Lee Thomasonce0763e2012-01-11 15:43:54 -080029#include <ctype.h>
30#include <stdio.h>
Lee Thomason2c85a712012-01-31 08:24:24 -080031#include <memory.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -080032
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080033/* TODO: create main page description.
34 TODO: add 'lastAttribute' for faster parsing.
35*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080036/*
37 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
38*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080039
U-Lama\Lee4cee6112011-12-31 14:58:18 -080040#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
41 #ifndef DEBUG
42 #define DEBUG
43 #endif
44#endif
45
46
47#if defined(DEBUG)
48 #if defined(_MSC_VER)
49 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
50 #elif defined (ANDROID_NDK)
51 #include <android/log.h>
52 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
53 #else
54 #include <assert.h>
55 #define TIXMLASSERT assert
56 #endif
57#else
58 #define TIXMLASSERT( x ) {}
59#endif
60
U-Lama\Leee13c3e62011-12-28 14:36:55 -080061
Lee Thomason1a1d4a72012-02-15 09:09:25 -080062// Deprecated library function hell. Compilers want to use the
63// new safe versions. This probably doesn't fully address the problem,
64// but it gets closer. There are too many compilers for me to fully
65// test. If you get compilation troubles, undefine TIXML_SAFE
66
67#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
68 // Microsoft visual studio, version 2005 and higher.
69 #define TIXML_SNPRINTF _snprintf_s
70 #define TIXML_SSCANF sscanf_s
71#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
72 // Microsoft visual studio, version 6 and higher.
73 //#pragma message( "Using _sn* functions." )
74 #define TIXML_SNPRINTF _snprintf
75 #define TIXML_SSCANF sscanf
76#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080077 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080078 //#warning( "Using sn* functions." )
79 #define TIXML_SNPRINTF snprintf
80 #define TIXML_SSCANF sscanf
81#else
82 #define TIXML_SNPRINTF snprintf
83 #define TIXML_SSCANF sscanf
84#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080085
86
U-Lama\Leee13c3e62011-12-28 14:36:55 -080087namespace tinyxml2
88{
Lee Thomasonce0763e2012-01-11 15:43:54 -080089class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080090class XMLElement;
91class XMLAttribute;
92class XMLComment;
93class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -080094class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -080095class XMLDeclaration;
96class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -080097
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080098class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -080099
U-Stream\Leeae25a442012-02-17 17:48:16 -0800100/*
101 A class that wraps strings. Normally stores the start and end
102 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800103 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800104 manage) a traditional char[]
105*/
Lee Thomason39ede242012-01-20 11:27:56 -0800106class StrPair
107{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800108public:
Lee Thomason39ede242012-01-20 11:27:56 -0800109 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800110 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800111 NEEDS_NEWLINE_NORMALIZATION = 0x02,
112
113 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
114 ATTRIBUTE_NAME = 0,
115 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
116 COMMENT = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason39ede242012-01-20 11:27:56 -0800117 };
118
119 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800120 ~StrPair();
121
Lee Thomasone4422302012-01-20 17:59:50 -0800122 void Set( char* start, char* end, int flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800123 Reset();
Lee Thomason39ede242012-01-20 11:27:56 -0800124 this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
125 }
126 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800127 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800128
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800129 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
130 void SetStr( const char* str, int flags=0 );
131
Lee Thomason56bdd022012-02-09 18:16:58 -0800132 char* ParseText( char* in, const char* endTag, int strFlags );
133 char* ParseName( char* in );
134
Lee Thomason2c85a712012-01-31 08:24:24 -0800135
Lee Thomason39ede242012-01-20 11:27:56 -0800136private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137 void Reset();
138
Lee Thomasone4422302012-01-20 17:59:50 -0800139 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800140 NEEDS_FLUSH = 0x100,
141 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800142 };
143
Lee Thomason39ede242012-01-20 11:27:56 -0800144 // After parsing, if *end != 0, it can be set to zero.
145 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800146 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800147 char* end;
148};
149
U-Lama\Lee560bd472011-12-28 19:42:49 -0800150
U-Stream\Leeae25a442012-02-17 17:48:16 -0800151/*
152 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
153 Has a small initial memory pool, so that low or no usage will not
154 cause a call to new/delete
155*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800156template <class T, int INIT>
157class DynArray
158{
159public:
160 DynArray< T, INIT >()
161 {
162 mem = pool;
163 allocated = INIT;
164 size = 0;
165 }
166 ~DynArray()
167 {
168 if ( mem != pool ) {
169 delete mem;
170 }
171 }
172 void Push( T t )
173 {
174 EnsureCapacity( size+1 );
175 mem[size++] = t;
176 }
177
178 T* PushArr( int count )
179 {
180 EnsureCapacity( size+count );
181 T* ret = &mem[size];
182 size += count;
183 return ret;
184 }
185 T Pop() {
186 return mem[--size];
187 }
188 void PopArr( int count )
189 {
190 TIXMLASSERT( size >= count );
191 size -= count;
192 }
193
U-Stream\Leeae25a442012-02-17 17:48:16 -0800194 bool Empty() const { return size == 0; }
195 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
196 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
197 int Size() const { return size; }
198 int Capacity() const { return allocated; }
199 const T* Mem() const { return mem; }
200 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800201
202
203private:
204 void EnsureCapacity( int cap ) {
205 if ( cap > allocated ) {
206 int newAllocated = cap * 2;
207 T* newMem = new T[newAllocated];
208 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
209 if ( mem != pool ) delete [] mem;
210 mem = newMem;
211 allocated = newAllocated;
212 }
213 }
214
215 T* mem;
216 T pool[INIT];
217 int allocated; // objects allocated
218 int size; // number objects in use
219};
220
Lee Thomason50adb4c2012-02-13 15:07:09 -0800221
U-Stream\Leeae25a442012-02-17 17:48:16 -0800222/*
223 Parent virtual class a a pool for fast allocation
224 and deallocation of objects.
225*/
Lee Thomasond1983222012-02-06 08:41:24 -0800226class MemPool
227{
228public:
229 MemPool() {}
230 virtual ~MemPool() {}
231
232 virtual int ItemSize() const = 0;
233 virtual void* Alloc() = 0;
234 virtual void Free( void* ) = 0;
235};
236
Lee Thomason50adb4c2012-02-13 15:07:09 -0800237
U-Stream\Leeae25a442012-02-17 17:48:16 -0800238/*
239 Template child class to create pools of the correct type.
240*/
Lee Thomasond1983222012-02-06 08:41:24 -0800241template< int SIZE >
242class MemPoolT : public MemPool
243{
244public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800245 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800246 ~MemPoolT() {
247 // Delete the blocks.
248 for( int i=0; i<blockPtrs.Size(); ++i ) {
249 delete blockPtrs[i];
250 }
251 }
252
253 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800254 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800255
256 virtual void* Alloc() {
257 if ( !root ) {
258 // Need a new block.
259 Block* block = new Block();
260 blockPtrs.Push( block );
261
262 for( int i=0; i<COUNT-1; ++i ) {
263 block->chunk[i].next = &block->chunk[i+1];
264 }
265 block->chunk[COUNT-1].next = 0;
266 root = block->chunk;
267 }
268 void* result = root;
269 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800270
271 ++currentAllocs;
272 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
273 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800274 return result;
275 }
276 virtual void Free( void* mem ) {
277 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800278 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800279 Chunk* chunk = (Chunk*)mem;
280 memset( chunk, 0xfe, sizeof(Chunk) );
281 chunk->next = root;
282 root = chunk;
283 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800284 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800285 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
286 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800287 }
Lee Thomasond1983222012-02-06 08:41:24 -0800288
289private:
290 enum { COUNT = 1024/SIZE };
291 union Chunk {
292 Chunk* next;
293 char mem[SIZE];
294 };
295 struct Block {
296 Chunk chunk[COUNT];
297 };
298 DynArray< Block*, 10 > blockPtrs;
299 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800300
301 int currentAllocs;
302 int nAllocs;
303 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800304};
305
Lee Thomason2c85a712012-01-31 08:24:24 -0800306
Lee Thomason56bdd022012-02-09 18:16:58 -0800307
308/**
309 Implements the interface to the "Visitor pattern" (see the Accept() method.)
310 If you call the Accept() method, it requires being passed a XMLVisitor
311 class to handle callbacks. For nodes that contain other nodes (Document, Element)
312 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
313 are simply called with Visit().
314
315 If you return 'true' from a Visit method, recursive parsing will continue. If you return
316 false, <b>no children of this node or its sibilings</b> will be Visited.
317
318 All flavors of Visit methods have a default implementation that returns 'true' (continue
319 visiting). You need to only override methods that are interesting to you.
320
321 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
322
323 You should never change the document from a callback.
324
325 @sa XMLNode::Accept()
326*/
327class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800328{
329public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800330 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800331
Lee Thomason56bdd022012-02-09 18:16:58 -0800332 /// Visit a document.
333 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
334 /// Visit a document.
335 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
336
337 /// Visit an element.
338 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
339 /// Visit an element.
340 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
341
342 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800343 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800344 /// Visit a text node
345 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
346 /// Visit a comment node
347 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
348 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800349 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800350};
351
352
U-Stream\Leeae25a442012-02-17 17:48:16 -0800353/*
354 Utility functionality.
355*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800356class XMLUtil
357{
Lee Thomasond1983222012-02-06 08:41:24 -0800358public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800359 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
360 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800361 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
362 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800363
364 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
365 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800366 if ( p == q ) {
367 return true;
368 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800369 while( *p && *q && *p == *q && n<nChar ) {
370 ++p; ++q; ++n;
371 }
372 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
373 return true;
374 }
375 return false;
376 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800377 inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800378 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
379 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800380
381 static const char* ReadBOM( const char* p, bool* hasBOM );
382 // p is the starting location,
383 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800384 static const char* GetCharacterRef( const char* p, char* value, int* length );
385 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800386};
387
Lee Thomason5cae8972012-01-24 18:03:07 -0800388
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800389/** XMLNode is a base class for every object that is in the
390 XML Document Object Model (DOM), except XMLAttributes.
391 Nodes have siblings, a parent, and children which can
392 be navigated. A node is always in a XMLDocument.
393 The type of a TiXmlNode can be queried, and it can
394 be cast to its more defined type.
395
396 An XMLDocument allocates memory for all its Nodes.
397 When the XMLDocument gets deleted, all its Nodes
398 will also be deleted.
399
400 @verbatim
401 A Document can contain: Element (container or leaf)
402 Comment (leaf)
403 Unknown (leaf)
404 Declaration( leaf )
405
406 An Element can contain: Element (container or leaf)
407 Text (leaf)
408 Attributes (not on tree)
409 Comment (leaf)
410 Unknown (leaf)
411
412 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800413*/
Lee Thomasond1983222012-02-06 08:41:24 -0800414class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800415{
416 friend class XMLDocument;
417 friend class XMLElement;
418public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800419
420 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800421 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800422 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800423 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800424
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800425 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
426 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
427 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
428 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
429 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
430 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800431
Lee Thomason50f97b22012-02-11 16:33:40 -0800432 virtual const XMLElement* ToElement() const { return 0; }
433 virtual const XMLText* ToText() const { return 0; }
434 virtual const XMLComment* ToComment() const { return 0; }
435 virtual const XMLDocument* ToDocument() const { return 0; }
436 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
437 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800438
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800439 /** The meaning of 'value' changes for the specific type.
440 @verbatim
441 Document: empy
442 Element: name of the element
443 Comment: the comment text
444 Unknown: the tag contents
445 Text: the text string
446 @endverbatim
447 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800448 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800449 /** Set the Value of an XML node.
450 @sa Value()
451 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800452 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800453
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800454 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800455 const XMLNode* Parent() const { return parent; }
456 XMLNode* Parent() { return parent; }
457
Lee Thomason50f97b22012-02-11 16:33:40 -0800458 /// Returns true if this node has no children.
459 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800460
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800461 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800462 const XMLNode* FirstChild() const { return firstChild; }
463 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800464 /** Get the first child element, or optionally the first child
465 element with the specified name.
466 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800467 const XMLElement* FirstChildElement( const char* value=0 ) const;
468 XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800470 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800471 const XMLNode* LastChild() const { return lastChild; }
472 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800474 /** Get the last child element or optionally the last child
475 element with the specified name.
476 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800477 const XMLElement* LastChildElement( const char* value=0 ) const;
478 XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); }
479
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800480 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800481 const XMLNode* PreviousSibling() const { return prev; }
482 XMLNode* PreviousSibling() { return prev; }
483
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800484 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800485 const XMLNode* PreviousSiblingElement( const char* value=0 ) const ;
486 XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
487
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800488 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800489 const XMLNode* NextSibling() const { return next; }
490 XMLNode* NextSibling() { return next; }
491
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800492 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800493 const XMLNode* NextSiblingElement( const char* value=0 ) const;
494 XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
495
Lee Thomason1ff38e02012-02-14 18:18:16 -0800496 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800497 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800498 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800499 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800500 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800501 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800502 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800503 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800504 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800505 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800506 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800507 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
508
U-Stream\Leeae25a442012-02-17 17:48:16 -0800509 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800510 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800511 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800512 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800513
514 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800515 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800516 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800517 void DeleteChild( XMLNode* node );
518
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800519 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
520 XML tree will be conditionally visited and the host will be called back
521 via the TiXmlVisitor interface.
522
523 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
524 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
525 interface versus any other.)
526
527 The interface has been based on ideas from:
528
529 - http://www.saxproject.org/
530 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
531
532 Which are both good references for "visiting".
533
534 An example of using Accept():
535 @verbatim
536 TiXmlPrinter printer;
537 tinyxmlDoc.Accept( &printer );
538 const char* xmlcstr = printer.CStr();
539 @endverbatim
540 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800541 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800542
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800543 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800544 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800545
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800546protected:
547 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800548 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800549 XMLNode( const XMLNode& ); // not supported
550 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800551
Lee Thomason3f57d272012-01-11 15:30:03 -0800552 XMLDocument* document;
553 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800554 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800555
556 XMLNode* firstChild;
557 XMLNode* lastChild;
558
559 XMLNode* prev;
560 XMLNode* next;
561
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800562private:
Lee Thomasond1983222012-02-06 08:41:24 -0800563 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800564 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800565};
566
567
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800568/** XML text.
569
570 Note that a text node can have child element nodes, for example:
571 @verbatim
572 <root>This is <b>bold</b></root>
573 @endverbatim
574
575 A text node can have 2 ways to output the next. "normal" output
576 and CDATA. It will default to the mode it was parsed from the XML file and
577 you generally want to leave it alone, but you can change the output mode with
578 SetCDATA() and query it with CDATA().
579*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800580class XMLText : public XMLNode
581{
Lee Thomason2c85a712012-01-31 08:24:24 -0800582 friend class XMLBase;
583 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800584public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800585 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800586
Lee Thomason751da522012-02-10 08:50:51 -0800587 virtual XMLText* ToText() { return this; }
588 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800589
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800590 /// Declare whether this should be CDATA or standard text.
591 void SetCData( bool isCData ) { this->isCData = isCData; }
592 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800593 bool CData() const { return isCData; }
594
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800595 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800596
597protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800598 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
599 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800600 XMLText( const XMLText& ); // not supported
601 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800602
603private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800604 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800605};
606
607
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800608/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800609class XMLComment : public XMLNode
610{
Lee Thomason2c85a712012-01-31 08:24:24 -0800611 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800612public:
Lee Thomason751da522012-02-10 08:50:51 -0800613 virtual XMLComment* ToComment() { return this; }
614 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800615
Lee Thomason56bdd022012-02-09 18:16:58 -0800616 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800617
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800618 char* ParseDeep( char*, StrPair* endTag );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800619
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800620protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800621 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800622 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800623 XMLComment( const XMLComment& ); // not supported
624 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800625
Lee Thomason3f57d272012-01-11 15:30:03 -0800626private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800627};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800628
629
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800630/** In correct XML the declaration is the first entry in the file.
631 @verbatim
632 <?xml version="1.0" standalone="yes"?>
633 @endverbatim
634
635 TinyXML2 will happily read or write files without a declaration,
636 however.
637
638 The text of the declaration isn't interpreted. It is parsed
639 and written as a string.
640*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800641class XMLDeclaration : public XMLNode
642{
643 friend class XMLDocument;
644public:
645 virtual XMLDeclaration* ToDeclaration() { return this; }
646 virtual const XMLDeclaration* ToDeclaration() const { return this; }
647
648 virtual bool Accept( XMLVisitor* visitor ) const;
649
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800650 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800651
652protected:
653 XMLDeclaration( XMLDocument* doc );
654 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800655 XMLDeclaration( const XMLDeclaration& ); // not supported
656 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800657};
658
659
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800660/** Any tag that tinyXml doesn't recognize is saved as an
661 unknown. It is a tag of text, but should not be modified.
662 It will be written back to the XML, unchanged, when the file
663 is saved.
664
665 DTD tags get thrown into TiXmlUnknowns.
666*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800667class XMLUnknown : public XMLNode
668{
669 friend class XMLDocument;
670public:
671 virtual XMLUnknown* ToUnknown() { return this; }
672 virtual const XMLUnknown* ToUnknown() const { return this; }
673
674 virtual bool Accept( XMLVisitor* visitor ) const;
675
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800676 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800677
678protected:
679 XMLUnknown( XMLDocument* doc );
680 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800681 XMLUnknown( const XMLUnknown& ); // not supported
682 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800683};
684
685
Lee Thomason1ff38e02012-02-14 18:18:16 -0800686enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800687 XML_NO_ERROR = 0,
688
Lee Thomason1ff38e02012-02-14 18:18:16 -0800689 NO_ATTRIBUTE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800690 WRONG_ATTRIBUTE_TYPE,
691
692 ERROR_FILE_NOT_FOUND,
693 ERROR_ELEMENT_MISMATCH,
694 ERROR_PARSING_ELEMENT,
695 ERROR_PARSING_ATTRIBUTE,
696 ERROR_IDENTIFYING_TAG,
697 ERROR_PARSING_TEXT,
698 ERROR_PARSING_CDATA,
699 ERROR_PARSING_COMMENT,
700 ERROR_PARSING_DECLARATION,
Lee Thomasond6277762012-02-22 16:00:12 -0800701 ERROR_PARSING_UNKNOWN,
702 ERROR_EMPTY_DOCUMENT,
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800703 ERROR_MISMATCHED_ELEMENT,
704 ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705};
706
707
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800708/** An attribute is a name-value pair. Elements have an arbitrary
709 number of attributes, each with a unique name.
710
711 @note The attributes are not XMLNodes. You may only query the
712 Next() attribute in a list.
713*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800714class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800715{
716 friend class XMLElement;
717public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800718 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
719 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
720 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800721
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800722 /** IntAttribute interprets the attribute as an integer, and returns the value.
723 If the value isn't an integer, 0 will be returned. There is no error checking;
724 use QueryIntAttribute() if you need error checking.
725 */
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800726 int IntAttribute() const { int i=0; QueryIntAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800727 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800728 unsigned UnsignedAttribute() const { unsigned i=0; QueryUnsignedAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800729 /// Query as a boolean. See IntAttribute()
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800730 bool BoolAttribute() const { bool b=false; QueryBoolAttribute( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800731 /// Query as a double. See IntAttribute()
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800732 double DoubleAttribute() const { double d=0; QueryDoubleAttribute( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800733 /// Query as a float. See IntAttribute()
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800734 float FloatAttribute() const { float f=0; QueryFloatAttribute( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800735
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800736 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
737 in the provided paremeter. The function will return XML_NO_ERROR on success,
738 and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
739 */
Lee Thomason1ff38e02012-02-14 18:18:16 -0800740 int QueryIntAttribute( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800741 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800742 int QueryUnsignedAttribute( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800743 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800744 int QueryBoolAttribute( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800745 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800746 int QueryDoubleAttribute( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800747 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800748 int QueryFloatAttribute( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800749
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800750 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800752 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800754 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800755 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800756 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800757 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800758 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800759 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800760 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800761 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800762
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800763private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800764 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800765
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800766 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800767 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800768 XMLAttribute( const XMLAttribute& ); // not supported
769 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800770 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800771
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800772 char* ParseDeep( char* p );
773
Lee Thomason751da522012-02-10 08:50:51 -0800774 mutable StrPair name;
775 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800776 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800777 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800778};
779
780
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800781/** The element is a container class. It has a value, the element name,
782 and can contain other elements, text, comments, and unknowns.
783 Elements also contain an arbitrary number of attributes.
784*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800785class XMLElement : public XMLNode
786{
Lee Thomason2c85a712012-01-31 08:24:24 -0800787 friend class XMLBase;
788 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800789public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800790 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800791 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800794
Lee Thomason751da522012-02-10 08:50:51 -0800795 virtual XMLElement* ToElement() { return this; }
796 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800797 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800798
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800799 /** Given an attribute name, Attribute() returns the value
800 for the attribute of that name, or null if none exists.
801 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800802 const char* Attribute( const char* name ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return 0; return a->Value(); }
Lee Thomason751da522012-02-10 08:50:51 -0800803
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800804 /** Given an attribute name, IntAttribute() returns the value
805 of the attribute interpreted as an integer. 0 will be
806 returned if there is an error. For a method with error
807 checking, see QueryIntAttribute()
808 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800809 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800810 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800811 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800812 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800813 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800814 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800815 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800816 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800817 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
818
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800819 /** Given an attribute name, QueryIntAttribute() returns
820 XML_NO_ERROR, WRONG_ATTRIBUTE_TYPE if the conversion
821 can't be performed, or NO_ATTRIBUTE if the attribute
822 doesn't exist. If successful, the result of the conversion
823 will be written to 'value'. If not successful, nothing will
824 be written to 'value'. This allows you to provide default
825 value:
826
827 @verbatim
828 int value = 10;
829 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
830 @endverbatim
831 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800832 int QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800833 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800834 int QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800835 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800836 int QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800837 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800838 int QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800839 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800840 int QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800841
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800842 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800843 void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800844 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800845 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800846 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800847 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800848 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800849 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800850 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800851 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800852
U-Stream\Leeae25a442012-02-17 17:48:16 -0800853 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800854 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800855 */
856 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800857
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800858 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800859 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800860 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800861 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800862
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800863 /** Convenience function for easy access to the text inside an element. Although easy
864 and concise, GetText() is limited compared to getting the TiXmlText child
865 and accessing it directly.
866
867 If the first child of 'this' is a TiXmlText, the GetText()
868 returns the character string of the Text node, else null is returned.
869
870 This is a convenient method for getting the text of simple contained text:
871 @verbatim
872 <foo>This is text</foo>
873 const char* str = fooElement->GetText();
874 @endverbatim
875
876 'str' will be a pointer to "This is text".
877
878 Note that this function can be misleading. If the element foo was created from
879 this XML:
880 @verbatim
881 <foo><b>This is text</b></foo>
882 @endverbatim
883
884 then the value of str would be null. The first child node isn't a text node, it is
885 another element. From this XML:
886 @verbatim
887 <foo>This is <b>text</b></foo>
888 @endverbatim
889 GetText() will return "This is ".
890 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800891 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800892
Lee Thomason2c85a712012-01-31 08:24:24 -0800893 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800894 enum {
895 OPEN, // <foo>
896 CLOSED, // <foo/>
897 CLOSING // </foo>
898 };
899 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800900 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800901
Lee Thomason50adb4c2012-02-13 15:07:09 -0800902private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800903 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800904 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800905 XMLElement( const XMLElement& ); // not supported
906 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800907
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800908 XMLAttribute* FindAttribute( const char* name );
909 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800910 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800911 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800912
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800913 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800914 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800915};
916
917
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800918/** A document binds together all the functionality.
919 It can be saved, loaded, and printed to the screen.
920 All Nodes are connected and allocated to a Document.
921 If the Document is deleted, all its Nodes are also deleted.
922*/
Lee Thomason67d61312012-01-24 16:01:51 -0800923class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800924{
Lee Thomasond1983222012-02-06 08:41:24 -0800925 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800926public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800927 /// constructor
Lee Thomason18d68bd2012-01-26 18:17:26 -0800928 XMLDocument();
Lee Thomason3f57d272012-01-11 15:30:03 -0800929 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800930
Lee Thomason751da522012-02-10 08:50:51 -0800931 virtual XMLDocument* ToDocument() { return this; }
932 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800933
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800934 /**
935 Parse an XML file from a character string.
936 Returns XML_NO_ERROR (0) on success, or
937 an errorID.
938 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800939 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800940 /**
941 Load an XML file from disk.
942 Returns XML_NO_ERROR (0) on success, or
943 an errorID.
944 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800945 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800946 /**
947 Load an XML file from disk. You are responsible
948 for providing and closing the FILE*.
949
950 Returns XML_NO_ERROR (0) on success, or
951 an errorID.
952 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800953 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800954 /**
955 Save the XML file to disk.
956 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800957 void SaveFile( const char* filename );
958
959 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800960
961 /** Return the root element of DOM. Equivalent to FirstChildElement().
962 To get the first node, use FirstChild().
963 */
Lee Thomasond6277762012-02-22 16:00:12 -0800964 XMLElement* RootElement() { return FirstChildElement(); }
965 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800966
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800967 /** Print the Document. If the Printer is not provided, it will
968 print to stdout. If you provide Printer, this can print to a file:
969 @verbatim
970 XMLPrinter printer( fp );
971 doc.Print( &printer );
972 @endverbatim
973
974 Or you can use a printer to print to memory:
975 @verbatim
976 XMLPrinter printer;
977 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -0800978 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800979 @endverbatim
980 */
981 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -0800982 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800983
Lee Thomason1ff38e02012-02-14 18:18:16 -0800984 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800985 Create a new Element associated with
986 this Document. The memory for the Element
987 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800988 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800989 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800990 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800991 Create a new Comment associated with
992 this Document. The memory for the Comment
993 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800994 */
995 XMLComment* NewComment( const char* comment );
996 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800997 Create a new Text associated with
998 this Document. The memory for the Text
999 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001000 */
1001 XMLText* NewText( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001002
U-Stream\Leeae25a442012-02-17 17:48:16 -08001003 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001004 Delete a node associated with this documented.
1005 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001006 */
1007 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1008
Lee Thomason67d61312012-01-24 16:01:51 -08001009 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001010
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001011 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001012 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001013 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001014 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001015 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001016 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001017 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001018 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001019 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001020 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001021
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001022 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001023 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001024
Lee Thomason3f57d272012-01-11 15:30:03 -08001025private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001026 XMLDocument( const XMLDocument& ); // not supported
1027 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001028 void InitDocument();
1029
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001030 bool writeBOM;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001031 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001032 const char* errorStr1;
1033 const char* errorStr2;
1034 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001035
1036 MemPoolT< sizeof(XMLElement) > elementPool;
1037 MemPoolT< sizeof(XMLAttribute) > attributePool;
1038 MemPoolT< sizeof(XMLText) > textPool;
1039 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001040};
1041
Lee Thomason7c913cd2012-01-26 18:32:34 -08001042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001043
1044/**
1045 Printing functionality. The XMLPrinter gives you more
1046 options than the XMLDocument::Print() method.
1047
1048 It can:
1049 -# Print to memory.
1050 -# Print to a file you provide
1051 -# Print XML without a XMLDocument.
1052
1053 Print to Memory
1054
1055 @verbatim
1056 XMLPrinter printer;
1057 doc->Print( &printer );
1058 SomeFunctior( printer.CStr() );
1059 @endverbatim
1060
1061 Print to a File
1062
1063 You provide the file pointer.
1064 @verbatim
1065 XMLPrinter printer( fp );
1066 doc.Print( &printer );
1067 @endverbatim
1068
1069 Print without a XMLDocument
1070
1071 When loading, an XML parser is very useful. However, sometimes
1072 when saving, it just gets in the way. The code is often set up
1073 for streaming, and constructing the DOM is just overhead.
1074
1075 The Printer supports the streaming case. The following code
1076 prints out a trivially simple XML file without ever creating
1077 an XML document.
1078
1079 @verbatim
1080 XMLPrinter printer( fp );
1081 printer.OpenElement( "foo" );
1082 printer.PushAttribute( "foo", "bar" );
1083 printer.CloseElement();
1084 @endverbatim
1085*/
1086class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001087{
1088public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001089 /** Construct the printer. If the FILE* is specified,
1090 this will print to the FILE. Else it will print
1091 to memory, and the result is available in CStr()
1092 */
1093 XMLPrinter( FILE* file=0 );
1094 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001095
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001096 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001097 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001098 /** If streaming, start writing an element.
1099 The element must be closed with CloseElement()
1100 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001101 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001102 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001103 void PushAttribute( const char* name, const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001104 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001105 void CloseElement();
1106
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001107 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001108 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001109 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001110 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001111
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001112 void PushDeclaration( const char* value );
1113 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001114
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001115 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001116 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1117
1118 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1119 virtual bool VisitExit( const XMLElement& element );
1120
1121 virtual bool Visit( const XMLText& text );
1122 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001123 virtual bool Visit( const XMLDeclaration& declaration );
1124 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001125
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001126 /**
1127 If in print to memory mode, return a pointer to
1128 the XML file in memory.
1129 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001130 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001131
Lee Thomason5cae8972012-01-24 18:03:07 -08001132private:
1133 void SealElement();
1134 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001135 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001136 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001137
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001138 bool elementJustOpened;
1139 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001140 FILE* fp;
1141 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001142 int textDepth;
1143
Lee Thomason857b8682012-01-25 17:50:25 -08001144 enum {
Lee Thomason951d8832012-01-26 08:47:06 -08001145 ENTITY_RANGE = 64
Lee Thomason857b8682012-01-25 17:50:25 -08001146 };
1147 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001148 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001149
Lee Thomason2c85a712012-01-31 08:24:24 -08001150 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001151 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001152};
1153
1154
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001155}; // tinyxml2
1156
U-Lama\Lee560bd472011-12-28 19:42:49 -08001157
1158
U-Stream\Leeae25a442012-02-17 17:48:16 -08001159#endif // TINYXML2_INCLUDED