blob: d9dee4d115819b220fb8af8c05f860a59d89cf67 [file] [log] [blame]
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -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*/
23
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*/
36
U-Lama\Lee4cee6112011-12-31 14:58:18 -080037#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
38 #ifndef DEBUG
39 #define DEBUG
40 #endif
41#endif
42
43
44#if defined(DEBUG)
45 #if defined(_MSC_VER)
46 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
47 #elif defined (ANDROID_NDK)
48 #include <android/log.h>
49 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
50 #else
51 #include <assert.h>
52 #define TIXMLASSERT assert
53 #endif
54#else
55 #define TIXMLASSERT( x ) {}
56#endif
57
U-Lama\Leee13c3e62011-12-28 14:36:55 -080058
Lee Thomason1a1d4a72012-02-15 09:09:25 -080059// Deprecated library function hell. Compilers want to use the
60// new safe versions. This probably doesn't fully address the problem,
61// but it gets closer. There are too many compilers for me to fully
62// test. If you get compilation troubles, undefine TIXML_SAFE
63
64#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
65 // Microsoft visual studio, version 2005 and higher.
66 #define TIXML_SNPRINTF _snprintf_s
67 #define TIXML_SSCANF sscanf_s
68#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
69 // Microsoft visual studio, version 6 and higher.
70 //#pragma message( "Using _sn* functions." )
71 #define TIXML_SNPRINTF _snprintf
72 #define TIXML_SSCANF sscanf
73#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080074 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080075 //#warning( "Using sn* functions." )
76 #define TIXML_SNPRINTF snprintf
77 #define TIXML_SSCANF sscanf
78#else
79 #define TIXML_SNPRINTF snprintf
80 #define TIXML_SSCANF sscanf
81#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080082
83
U-Lama\Leee13c3e62011-12-28 14:36:55 -080084namespace tinyxml2
85{
Lee Thomasonce0763e2012-01-11 15:43:54 -080086class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080087class XMLElement;
88class XMLAttribute;
89class XMLComment;
90class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -080091class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -080092class XMLDeclaration;
93class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -080094
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080095class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -080096
U-Stream\Leeae25a442012-02-17 17:48:16 -080097/*
98 A class that wraps strings. Normally stores the start and end
99 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800100 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800101 manage) a traditional char[]
102*/
Lee Thomason39ede242012-01-20 11:27:56 -0800103class StrPair
104{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800105public:
Lee Thomason39ede242012-01-20 11:27:56 -0800106 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800107 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800108 NEEDS_NEWLINE_NORMALIZATION = 0x02,
109
110 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
111 ATTRIBUTE_NAME = 0,
112 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
113 COMMENT = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason39ede242012-01-20 11:27:56 -0800114 };
115
116 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800117 ~StrPair();
118
Lee Thomasone4422302012-01-20 17:59:50 -0800119 void Set( char* start, char* end, int flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800120 Reset();
Lee Thomason39ede242012-01-20 11:27:56 -0800121 this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
122 }
123 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800124 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800125
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
127 void SetStr( const char* str, int flags=0 );
128
Lee Thomason56bdd022012-02-09 18:16:58 -0800129 char* ParseText( char* in, const char* endTag, int strFlags );
130 char* ParseName( char* in );
131
Lee Thomason2c85a712012-01-31 08:24:24 -0800132
Lee Thomason39ede242012-01-20 11:27:56 -0800133private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134 void Reset();
135
Lee Thomasone4422302012-01-20 17:59:50 -0800136 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137 NEEDS_FLUSH = 0x100,
138 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800139 };
140
Lee Thomason39ede242012-01-20 11:27:56 -0800141 // After parsing, if *end != 0, it can be set to zero.
142 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800143 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800144 char* end;
145};
146
U-Lama\Lee560bd472011-12-28 19:42:49 -0800147
U-Stream\Leeae25a442012-02-17 17:48:16 -0800148/*
149 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
150 Has a small initial memory pool, so that low or no usage will not
151 cause a call to new/delete
152*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800153template <class T, int INIT>
154class DynArray
155{
156public:
157 DynArray< T, INIT >()
158 {
159 mem = pool;
160 allocated = INIT;
161 size = 0;
162 }
163 ~DynArray()
164 {
165 if ( mem != pool ) {
166 delete mem;
167 }
168 }
169 void Push( T t )
170 {
171 EnsureCapacity( size+1 );
172 mem[size++] = t;
173 }
174
175 T* PushArr( int count )
176 {
177 EnsureCapacity( size+count );
178 T* ret = &mem[size];
179 size += count;
180 return ret;
181 }
182 T Pop() {
183 return mem[--size];
184 }
185 void PopArr( int count )
186 {
187 TIXMLASSERT( size >= count );
188 size -= count;
189 }
190
U-Stream\Leeae25a442012-02-17 17:48:16 -0800191 bool Empty() const { return size == 0; }
192 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
193 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
194 int Size() const { return size; }
195 int Capacity() const { return allocated; }
196 const T* Mem() const { return mem; }
197 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800198
199
200private:
201 void EnsureCapacity( int cap ) {
202 if ( cap > allocated ) {
203 int newAllocated = cap * 2;
204 T* newMem = new T[newAllocated];
205 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
206 if ( mem != pool ) delete [] mem;
207 mem = newMem;
208 allocated = newAllocated;
209 }
210 }
211
212 T* mem;
213 T pool[INIT];
214 int allocated; // objects allocated
215 int size; // number objects in use
216};
217
Lee Thomason50adb4c2012-02-13 15:07:09 -0800218
U-Stream\Leeae25a442012-02-17 17:48:16 -0800219/*
220 Parent virtual class a a pool for fast allocation
221 and deallocation of objects.
222*/
Lee Thomasond1983222012-02-06 08:41:24 -0800223class MemPool
224{
225public:
226 MemPool() {}
227 virtual ~MemPool() {}
228
229 virtual int ItemSize() const = 0;
230 virtual void* Alloc() = 0;
231 virtual void Free( void* ) = 0;
232};
233
Lee Thomason50adb4c2012-02-13 15:07:09 -0800234
U-Stream\Leeae25a442012-02-17 17:48:16 -0800235/*
236 Template child class to create pools of the correct type.
237*/
Lee Thomasond1983222012-02-06 08:41:24 -0800238template< int SIZE >
239class MemPoolT : public MemPool
240{
241public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800242 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800243 ~MemPoolT() {
244 // Delete the blocks.
245 for( int i=0; i<blockPtrs.Size(); ++i ) {
246 delete blockPtrs[i];
247 }
248 }
249
250 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800251 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800252
253 virtual void* Alloc() {
254 if ( !root ) {
255 // Need a new block.
256 Block* block = new Block();
257 blockPtrs.Push( block );
258
259 for( int i=0; i<COUNT-1; ++i ) {
260 block->chunk[i].next = &block->chunk[i+1];
261 }
262 block->chunk[COUNT-1].next = 0;
263 root = block->chunk;
264 }
265 void* result = root;
266 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800267
268 ++currentAllocs;
269 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
270 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800271 return result;
272 }
273 virtual void Free( void* mem ) {
274 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800275 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800276 Chunk* chunk = (Chunk*)mem;
277 memset( chunk, 0xfe, sizeof(Chunk) );
278 chunk->next = root;
279 root = chunk;
280 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800281 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800282 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
283 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800284 }
Lee Thomasond1983222012-02-06 08:41:24 -0800285
286private:
287 enum { COUNT = 1024/SIZE };
288 union Chunk {
289 Chunk* next;
290 char mem[SIZE];
291 };
292 struct Block {
293 Chunk chunk[COUNT];
294 };
295 DynArray< Block*, 10 > blockPtrs;
296 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800297
298 int currentAllocs;
299 int nAllocs;
300 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800301};
302
Lee Thomason2c85a712012-01-31 08:24:24 -0800303
Lee Thomason56bdd022012-02-09 18:16:58 -0800304
305/**
306 Implements the interface to the "Visitor pattern" (see the Accept() method.)
307 If you call the Accept() method, it requires being passed a XMLVisitor
308 class to handle callbacks. For nodes that contain other nodes (Document, Element)
309 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
310 are simply called with Visit().
311
312 If you return 'true' from a Visit method, recursive parsing will continue. If you return
313 false, <b>no children of this node or its sibilings</b> will be Visited.
314
315 All flavors of Visit methods have a default implementation that returns 'true' (continue
316 visiting). You need to only override methods that are interesting to you.
317
318 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
319
320 You should never change the document from a callback.
321
322 @sa XMLNode::Accept()
323*/
324class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800325{
326public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800327 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800328
Lee Thomason56bdd022012-02-09 18:16:58 -0800329 /// Visit a document.
330 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
331 /// Visit a document.
332 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
333
334 /// Visit an element.
335 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
336 /// Visit an element.
337 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
338
339 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800340 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800341 /// Visit a text node
342 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
343 /// Visit a comment node
344 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
345 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800346 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800347};
348
349
U-Stream\Leeae25a442012-02-17 17:48:16 -0800350/*
351 Utility functionality.
352*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800353class XMLUtil
354{
Lee Thomasond1983222012-02-06 08:41:24 -0800355public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800356 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
357 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800358 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
359 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800360
361 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
362 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800363 if ( p == q ) {
364 return true;
365 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800366 while( *p && *q && *p == *q && n<nChar ) {
367 ++p; ++q; ++n;
368 }
369 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
370 return true;
371 }
372 return false;
373 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800374 inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800375 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
376 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800377
378 static const char* ReadBOM( const char* p, bool* hasBOM );
379 // p is the starting location,
380 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800381 static const char* GetCharacterRef( const char* p, char* value, int* length );
382 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800383};
384
Lee Thomason5cae8972012-01-24 18:03:07 -0800385
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800386/** XMLNode is a base class for every object that is in the
387 XML Document Object Model (DOM), except XMLAttributes.
388 Nodes have siblings, a parent, and children which can
389 be navigated. A node is always in a XMLDocument.
390 The type of a TiXmlNode can be queried, and it can
391 be cast to its more defined type.
392
393 An XMLDocument allocates memory for all its Nodes.
394 When the XMLDocument gets deleted, all its Nodes
395 will also be deleted.
396
397 @verbatim
398 A Document can contain: Element (container or leaf)
399 Comment (leaf)
400 Unknown (leaf)
401 Declaration( leaf )
402
403 An Element can contain: Element (container or leaf)
404 Text (leaf)
405 Attributes (not on tree)
406 Comment (leaf)
407 Unknown (leaf)
408
409 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800410*/
Lee Thomasond1983222012-02-06 08:41:24 -0800411class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800412{
413 friend class XMLDocument;
414 friend class XMLElement;
415public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800416
417 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800418 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800419 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800420 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800421
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800422 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
423 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
424 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
425 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
426 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
427 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800428
Lee Thomason50f97b22012-02-11 16:33:40 -0800429 virtual const XMLElement* ToElement() const { return 0; }
430 virtual const XMLText* ToText() const { return 0; }
431 virtual const XMLComment* ToComment() const { return 0; }
432 virtual const XMLDocument* ToDocument() const { return 0; }
433 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
434 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800435
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800436 /** The meaning of 'value' changes for the specific type.
437 @verbatim
438 Document: empy
439 Element: name of the element
440 Comment: the comment text
441 Unknown: the tag contents
442 Text: the text string
443 @endverbatim
444 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800445 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800446 /** Set the Value of an XML node.
447 @sa Value()
448 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800449 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800450
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800451 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800452 const XMLNode* Parent() const { return parent; }
453 XMLNode* Parent() { return parent; }
454
Lee Thomason50f97b22012-02-11 16:33:40 -0800455 /// Returns true if this node has no children.
456 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800458 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800459 const XMLNode* FirstChild() const { return firstChild; }
460 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800461 /** Get the first child element, or optionally the first child
462 element with the specified name.
463 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800464 const XMLElement* FirstChildElement( const char* value=0 ) const;
465 XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800466
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800467 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800468 const XMLNode* LastChild() const { return lastChild; }
469 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800470
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800471 /** Get the last child element or optionally the last child
472 element with the specified name.
473 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800474 const XMLElement* LastChildElement( const char* value=0 ) const;
475 XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); }
476
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800477 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800478 const XMLNode* PreviousSibling() const { return prev; }
479 XMLNode* PreviousSibling() { return prev; }
480
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800481 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800482 const XMLNode* PreviousSiblingElement( const char* value=0 ) const ;
483 XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
484
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800485 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800486 const XMLNode* NextSibling() const { return next; }
487 XMLNode* NextSibling() { return next; }
488
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800489 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800490 const XMLNode* NextSiblingElement( const char* value=0 ) const;
491 XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
492
Lee Thomason1ff38e02012-02-14 18:18:16 -0800493 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800494 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800495 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800496 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800497 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800498 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800499 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800500 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800501 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800502 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800503 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800504 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
505
U-Stream\Leeae25a442012-02-17 17:48:16 -0800506 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800507 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800508 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800509 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800510
511 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800512 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800513 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800514 void DeleteChild( XMLNode* node );
515
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800516 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
517 XML tree will be conditionally visited and the host will be called back
518 via the TiXmlVisitor interface.
519
520 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
521 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
522 interface versus any other.)
523
524 The interface has been based on ideas from:
525
526 - http://www.saxproject.org/
527 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
528
529 Which are both good references for "visiting".
530
531 An example of using Accept():
532 @verbatim
533 TiXmlPrinter printer;
534 tinyxmlDoc.Accept( &printer );
535 const char* xmlcstr = printer.CStr();
536 @endverbatim
537 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800538 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800539
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800540 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800541 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800542
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800543protected:
544 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800545 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800546 XMLNode( const XMLNode& ); // not supported
547 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800548
Lee Thomason3f57d272012-01-11 15:30:03 -0800549 XMLDocument* document;
550 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800551 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800552
553 XMLNode* firstChild;
554 XMLNode* lastChild;
555
556 XMLNode* prev;
557 XMLNode* next;
558
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800559private:
Lee Thomasond1983222012-02-06 08:41:24 -0800560 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800561 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800562};
563
564
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800565/** XML text.
566
567 Note that a text node can have child element nodes, for example:
568 @verbatim
569 <root>This is <b>bold</b></root>
570 @endverbatim
571
572 A text node can have 2 ways to output the next. "normal" output
573 and CDATA. It will default to the mode it was parsed from the XML file and
574 you generally want to leave it alone, but you can change the output mode with
575 SetCDATA() and query it with CDATA().
576*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800577class XMLText : public XMLNode
578{
Lee Thomason2c85a712012-01-31 08:24:24 -0800579 friend class XMLBase;
580 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800581public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800582 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800583
Lee Thomason751da522012-02-10 08:50:51 -0800584 virtual XMLText* ToText() { return this; }
585 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800586
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800587 /// Declare whether this should be CDATA or standard text.
588 void SetCData( bool isCData ) { this->isCData = isCData; }
589 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800590 bool CData() const { return isCData; }
591
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800592 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800593
594protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800595 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
596 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800597 XMLText( const XMLText& ); // not supported
598 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800599
600private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800601 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800602};
603
604
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800605/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800606class XMLComment : public XMLNode
607{
Lee Thomason2c85a712012-01-31 08:24:24 -0800608 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800609public:
Lee Thomason751da522012-02-10 08:50:51 -0800610 virtual XMLComment* ToComment() { return this; }
611 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800612
Lee Thomason56bdd022012-02-09 18:16:58 -0800613 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800614
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800615 char* ParseDeep( char*, StrPair* endTag );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800616
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800617protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800618 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800619 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800620 XMLComment( const XMLComment& ); // not supported
621 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622
Lee Thomason3f57d272012-01-11 15:30:03 -0800623private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800624};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800625
626
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800627/** In correct XML the declaration is the first entry in the file.
628 @verbatim
629 <?xml version="1.0" standalone="yes"?>
630 @endverbatim
631
632 TinyXML2 will happily read or write files without a declaration,
633 however.
634
635 The text of the declaration isn't interpreted. It is parsed
636 and written as a string.
637*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800638class XMLDeclaration : public XMLNode
639{
640 friend class XMLDocument;
641public:
642 virtual XMLDeclaration* ToDeclaration() { return this; }
643 virtual const XMLDeclaration* ToDeclaration() const { return this; }
644
645 virtual bool Accept( XMLVisitor* visitor ) const;
646
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800647 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800648
649protected:
650 XMLDeclaration( XMLDocument* doc );
651 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800652 XMLDeclaration( const XMLDeclaration& ); // not supported
653 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800654};
655
656
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800657/** Any tag that tinyXml doesn't recognize is saved as an
658 unknown. It is a tag of text, but should not be modified.
659 It will be written back to the XML, unchanged, when the file
660 is saved.
661
662 DTD tags get thrown into TiXmlUnknowns.
663*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800664class XMLUnknown : public XMLNode
665{
666 friend class XMLDocument;
667public:
668 virtual XMLUnknown* ToUnknown() { return this; }
669 virtual const XMLUnknown* ToUnknown() const { return this; }
670
671 virtual bool Accept( XMLVisitor* visitor ) const;
672
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800673 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800674
675protected:
676 XMLUnknown( XMLDocument* doc );
677 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800678 XMLUnknown( const XMLUnknown& ); // not supported
679 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800680};
681
682
Lee Thomason1ff38e02012-02-14 18:18:16 -0800683enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800684 XML_NO_ERROR = 0,
685
Lee Thomason1ff38e02012-02-14 18:18:16 -0800686 NO_ATTRIBUTE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800687 WRONG_ATTRIBUTE_TYPE,
688
689 ERROR_FILE_NOT_FOUND,
690 ERROR_ELEMENT_MISMATCH,
691 ERROR_PARSING_ELEMENT,
692 ERROR_PARSING_ATTRIBUTE,
693 ERROR_IDENTIFYING_TAG,
694 ERROR_PARSING_TEXT,
695 ERROR_PARSING_CDATA,
696 ERROR_PARSING_COMMENT,
697 ERROR_PARSING_DECLARATION,
Lee Thomasond6277762012-02-22 16:00:12 -0800698 ERROR_PARSING_UNKNOWN,
699 ERROR_EMPTY_DOCUMENT,
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800700 ERROR_MISMATCHED_ELEMENT,
701 ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800702};
703
704
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800705/** An attribute is a name-value pair. Elements have an arbitrary
706 number of attributes, each with a unique name.
707
708 @note The attributes are not XMLNodes. You may only query the
709 Next() attribute in a list.
710*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800711class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800712{
713 friend class XMLElement;
714public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800715 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
716 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
717 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800719 /** IntAttribute interprets the attribute as an integer, and returns the value.
720 If the value isn't an integer, 0 will be returned. There is no error checking;
721 use QueryIntAttribute() if you need error checking.
722 */
U-Stream\Leeae25a442012-02-17 17:48:16 -0800723 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800724 /// Query as an unsigned integer. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800725 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800726 /// Query as a boolean. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800727 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800728 /// Query as a double. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800729 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800730 /// Query as a float. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800731 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( &f ); return f; }
732
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800733 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
734 in the provided paremeter. The function will return XML_NO_ERROR on success,
735 and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
736 */
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737 int QueryIntAttribute( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800738 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800739 int QueryUnsignedAttribute( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800740 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800741 int QueryBoolAttribute( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800742 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800743 int QueryDoubleAttribute( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800744 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800745 int QueryFloatAttribute( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800746
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800747 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800748 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800749 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800751 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800752 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800753 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800754 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800755 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800756 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800757 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800758 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800759
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800760private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800761 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800762
Lee Thomasond1983222012-02-06 08:41:24 -0800763 XMLAttribute( XMLElement* element ) : next( 0 ) {}
764 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800765 XMLAttribute( const XMLAttribute& ); // not supported
766 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800767 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800768
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800769 char* ParseDeep( char* p );
770
Lee Thomason751da522012-02-10 08:50:51 -0800771 mutable StrPair name;
772 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800773 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800774 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800775};
776
777
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800778/** The element is a container class. It has a value, the element name,
779 and can contain other elements, text, comments, and unknowns.
780 Elements also contain an arbitrary number of attributes.
781*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800782class XMLElement : public XMLNode
783{
Lee Thomason2c85a712012-01-31 08:24:24 -0800784 friend class XMLBase;
785 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800786public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800787 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800788 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800789 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800790 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800791
Lee Thomason751da522012-02-10 08:50:51 -0800792 virtual XMLElement* ToElement() { return this; }
793 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800794 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800795
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800796 /** Given an attribute name, Attribute() returns the value
797 for the attribute of that name, or null if none exists.
798 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800799 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 -0800800
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800801 /** Given an attribute name, IntAttribute() returns the value
802 of the attribute interpreted as an integer. 0 will be
803 returned if there is an error. For a method with error
804 checking, see QueryIntAttribute()
805 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800806 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800807 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800808 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800809 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800810 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800811 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800812 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800813 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800814 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
815
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800816 /** Given an attribute name, QueryIntAttribute() returns
817 XML_NO_ERROR, WRONG_ATTRIBUTE_TYPE if the conversion
818 can't be performed, or NO_ATTRIBUTE if the attribute
819 doesn't exist. If successful, the result of the conversion
820 will be written to 'value'. If not successful, nothing will
821 be written to 'value'. This allows you to provide default
822 value:
823
824 @verbatim
825 int value = 10;
826 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
827 @endverbatim
828 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800829 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 -0800830 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800831 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 -0800832 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800833 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 -0800834 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800835 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 -0800836 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800837 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 -0800838
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800839 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800840 void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800841 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800842 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800843 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800844 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800845 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800846 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800847 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800848 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800849
U-Stream\Leeae25a442012-02-17 17:48:16 -0800850 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800851 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800852 */
853 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800854
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800855 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800856 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800857 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800858 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800859
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800860 /** Convenience function for easy access to the text inside an element. Although easy
861 and concise, GetText() is limited compared to getting the TiXmlText child
862 and accessing it directly.
863
864 If the first child of 'this' is a TiXmlText, the GetText()
865 returns the character string of the Text node, else null is returned.
866
867 This is a convenient method for getting the text of simple contained text:
868 @verbatim
869 <foo>This is text</foo>
870 const char* str = fooElement->GetText();
871 @endverbatim
872
873 'str' will be a pointer to "This is text".
874
875 Note that this function can be misleading. If the element foo was created from
876 this XML:
877 @verbatim
878 <foo><b>This is text</b></foo>
879 @endverbatim
880
881 then the value of str would be null. The first child node isn't a text node, it is
882 another element. From this XML:
883 @verbatim
884 <foo>This is <b>text</b></foo>
885 @endverbatim
886 GetText() will return "This is ".
887 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800888 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800889
Lee Thomason2c85a712012-01-31 08:24:24 -0800890 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800891 enum {
892 OPEN, // <foo>
893 CLOSED, // <foo/>
894 CLOSING // </foo>
895 };
896 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800897 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800898
Lee Thomason50adb4c2012-02-13 15:07:09 -0800899private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800900 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800901 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800902 XMLElement( const XMLElement& ); // not supported
903 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800904
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800905 XMLAttribute* FindAttribute( const char* name );
906 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800907 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800908 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800909
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800910 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800911 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800912};
913
914
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800915/** A document binds together all the functionality.
916 It can be saved, loaded, and printed to the screen.
917 All Nodes are connected and allocated to a Document.
918 If the Document is deleted, all its Nodes are also deleted.
919*/
Lee Thomason67d61312012-01-24 16:01:51 -0800920class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800921{
Lee Thomasond1983222012-02-06 08:41:24 -0800922 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800923public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800924 /// constructor
Lee Thomason18d68bd2012-01-26 18:17:26 -0800925 XMLDocument();
Lee Thomason3f57d272012-01-11 15:30:03 -0800926 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800927
Lee Thomason751da522012-02-10 08:50:51 -0800928 virtual XMLDocument* ToDocument() { return this; }
929 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800930
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800931 /**
932 Parse an XML file from a character string.
933 Returns XML_NO_ERROR (0) on success, or
934 an errorID.
935 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800936 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800937 /**
938 Load an XML file from disk.
939 Returns XML_NO_ERROR (0) on success, or
940 an errorID.
941 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800942 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800943 /**
944 Load an XML file from disk. You are responsible
945 for providing and closing the FILE*.
946
947 Returns XML_NO_ERROR (0) on success, or
948 an errorID.
949 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800950 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800951 /**
952 Save the XML file to disk.
953 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800954 void SaveFile( const char* filename );
955
956 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800957
958 /** Return the root element of DOM. Equivalent to FirstChildElement().
959 To get the first node, use FirstChild().
960 */
Lee Thomasond6277762012-02-22 16:00:12 -0800961 XMLElement* RootElement() { return FirstChildElement(); }
962 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800963
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800964 /** Print the Document. If the Printer is not provided, it will
965 print to stdout. If you provide Printer, this can print to a file:
966 @verbatim
967 XMLPrinter printer( fp );
968 doc.Print( &printer );
969 @endverbatim
970
971 Or you can use a printer to print to memory:
972 @verbatim
973 XMLPrinter printer;
974 doc->Print( &printer );
975 SomeFunctior( printer.CStr() );
976 @endverbatim
977 */
978 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -0800979 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800980
Lee Thomason1ff38e02012-02-14 18:18:16 -0800981 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800982 Create a new Element associated with
983 this Document. The memory for the Element
984 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800985 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800986 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800987 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800988 Create a new Comment associated with
989 this Document. The memory for the Comment
990 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800991 */
992 XMLComment* NewComment( const char* comment );
993 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800994 Create a new Text associated with
995 this Document. The memory for the Text
996 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800997 */
998 XMLText* NewText( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -0800999
U-Stream\Leeae25a442012-02-17 17:48:16 -08001000 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001001 Delete a node associated with this documented.
1002 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001003 */
1004 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1005
Lee Thomason67d61312012-01-24 16:01:51 -08001006 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001007
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001008 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001009 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001010 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001011 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001012 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001013 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001014 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001015 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001016 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001017 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001018
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001019 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001020 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001021
Lee Thomason3f57d272012-01-11 15:30:03 -08001022private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001023 XMLDocument( const XMLDocument& ); // not supported
1024 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001025 void InitDocument();
1026
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001027 bool writeBOM;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001028 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001029 const char* errorStr1;
1030 const char* errorStr2;
1031 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001032
1033 MemPoolT< sizeof(XMLElement) > elementPool;
1034 MemPoolT< sizeof(XMLAttribute) > attributePool;
1035 MemPoolT< sizeof(XMLText) > textPool;
1036 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001037};
1038
Lee Thomason7c913cd2012-01-26 18:32:34 -08001039
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001040
1041/**
1042 Printing functionality. The XMLPrinter gives you more
1043 options than the XMLDocument::Print() method.
1044
1045 It can:
1046 -# Print to memory.
1047 -# Print to a file you provide
1048 -# Print XML without a XMLDocument.
1049
1050 Print to Memory
1051
1052 @verbatim
1053 XMLPrinter printer;
1054 doc->Print( &printer );
1055 SomeFunctior( printer.CStr() );
1056 @endverbatim
1057
1058 Print to a File
1059
1060 You provide the file pointer.
1061 @verbatim
1062 XMLPrinter printer( fp );
1063 doc.Print( &printer );
1064 @endverbatim
1065
1066 Print without a XMLDocument
1067
1068 When loading, an XML parser is very useful. However, sometimes
1069 when saving, it just gets in the way. The code is often set up
1070 for streaming, and constructing the DOM is just overhead.
1071
1072 The Printer supports the streaming case. The following code
1073 prints out a trivially simple XML file without ever creating
1074 an XML document.
1075
1076 @verbatim
1077 XMLPrinter printer( fp );
1078 printer.OpenElement( "foo" );
1079 printer.PushAttribute( "foo", "bar" );
1080 printer.CloseElement();
1081 @endverbatim
1082*/
1083class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001084{
1085public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001086 /** Construct the printer. If the FILE* is specified,
1087 this will print to the FILE. Else it will print
1088 to memory, and the result is available in CStr()
1089 */
1090 XMLPrinter( FILE* file=0 );
1091 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001092
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001093 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001094 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001095 /** If streaming, start writing an element.
1096 The element must be closed with CloseElement()
1097 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001098 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001099 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001100 void PushAttribute( const char* name, const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001101 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001102 void CloseElement();
1103
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001104 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001105 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001106 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001107 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001108
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001109 void PushDeclaration( const char* value );
1110 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001111
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001112 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001113 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1114
1115 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1116 virtual bool VisitExit( const XMLElement& element );
1117
1118 virtual bool Visit( const XMLText& text );
1119 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001120 virtual bool Visit( const XMLDeclaration& declaration );
1121 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001122
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001123 /**
1124 If in print to memory mode, return a pointer to
1125 the XML file in memory.
1126 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001127 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001128
Lee Thomason5cae8972012-01-24 18:03:07 -08001129private:
1130 void SealElement();
1131 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001132 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001133 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001134
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001135 bool elementJustOpened;
1136 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001137 FILE* fp;
1138 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001139 int textDepth;
1140
Lee Thomason857b8682012-01-25 17:50:25 -08001141 enum {
Lee Thomason951d8832012-01-26 08:47:06 -08001142 ENTITY_RANGE = 64
Lee Thomason857b8682012-01-25 17:50:25 -08001143 };
1144 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001145 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001146
Lee Thomason2c85a712012-01-31 08:24:24 -08001147 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001148 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001149};
1150
1151
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001152}; // tinyxml2
1153
U-Lama\Lee560bd472011-12-28 19:42:49 -08001154
1155
U-Stream\Leeae25a442012-02-17 17:48:16 -08001156#endif // TINYXML2_INCLUDED