blob: 76e47ac98372c7cc1ad0b95f13aa0a04bcb419a9 [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 Thomason7d00b9a2012-02-27 17:54:22 -080024#ifndef TINYXML2_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025#define TINYXML2_INCLUDED
26
Lee Thomason5ce89412012-03-20 13:23:44 -070027#if 1
28 #include <cctype>
29 #include <climits>
30 #include <cstdio>
31 #include <cstring>
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070032 #include <cstdarg>
Lee Thomason5ce89412012-03-20 13:23:44 -070033#else
34 // Not completely sure all the interesting systems
35 // can handle the new headers; can switch this if
36 // there is an include problem.
37 #include <limits.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <memory.h> // Needed by mac.
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -070041#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080042
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070043
Lee Thomason7d00b9a2012-02-27 17:54:22 -080044/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080045 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080046 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080047*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080048/*
49 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
50*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080051
U-Lama\Lee4cee6112011-12-31 14:58:18 -080052#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
53 #ifndef DEBUG
54 #define DEBUG
55 #endif
56#endif
57
58
59#if defined(DEBUG)
60 #if defined(_MSC_VER)
Guillermo A. Amaral68b0c872012-03-24 11:07:19 -070061 #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
U-Lama\Lee4cee6112011-12-31 14:58:18 -080062 #elif defined (ANDROID_NDK)
63 #include <android/log.h>
64 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
65 #else
66 #include <assert.h>
67 #define TIXMLASSERT assert
68 #endif
69#else
70 #define TIXMLASSERT( x ) {}
71#endif
72
U-Lama\Leee13c3e62011-12-28 14:36:55 -080073
Lee Thomason1a1d4a72012-02-15 09:09:25 -080074#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
75 // Microsoft visual studio, version 2005 and higher.
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070076 /*int _snprintf_s(
77 char *buffer,
78 size_t sizeOfBuffer,
79 size_t count,
80 const char *format [,
81 argument] ...
82 );*/
83 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) {
84 va_list va;
85 va_start( va, format );
86 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
87 va_end( va );
88 return result;
89 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -080090 #define TIXML_SSCANF sscanf_s
Lee Thomason (grinliz)b9e791f2012-04-06 21:27:10 -070091#else
U-Stream\Leeae25a442012-02-17 17:48:16 -080092 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080093 //#warning( "Using sn* functions." )
94 #define TIXML_SNPRINTF snprintf
95 #define TIXML_SSCANF sscanf
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080097
Lee Thomason7f7b1622012-03-24 12:49:03 -070098static const int TIXML2_MAJOR_VERSION = 0;
99static const int TIXML2_MINOR_VERSION = 9;
Lee Thomason (grinliz)87127572012-04-07 20:56:38 -0700100static const int TIXML2_PATCH_VERSION = 4;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800101
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800102namespace tinyxml2
103{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800104class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800105class XMLElement;
106class XMLAttribute;
107class XMLComment;
108class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800109class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800110class XMLDeclaration;
111class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800112
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800113class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800114
U-Stream\Leeae25a442012-02-17 17:48:16 -0800115/*
116 A class that wraps strings. Normally stores the start and end
117 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800118 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800119 manage) a traditional char[]
120*/
Lee Thomason39ede242012-01-20 11:27:56 -0800121class StrPair
122{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800123public:
Lee Thomason39ede242012-01-20 11:27:56 -0800124 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800125 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800126 NEEDS_NEWLINE_NORMALIZATION = 0x02,
127
128 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800129 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800130 ATTRIBUTE_NAME = 0,
131 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800132 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700133 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800134 };
135
136 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137 ~StrPair();
138
Lee Thomason5ce89412012-03-20 13:23:44 -0700139 void Set( char* _start, char* _end, int _flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800140 Reset();
Lee Thomason5ce89412012-03-20 13:23:44 -0700141 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800142 }
143 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800144 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800145
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700146 void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800147 void SetStr( const char* str, int flags=0 );
148
Lee Thomason56bdd022012-02-09 18:16:58 -0800149 char* ParseText( char* in, const char* endTag, int strFlags );
150 char* ParseName( char* in );
151
Lee Thomason2c85a712012-01-31 08:24:24 -0800152
Lee Thomason39ede242012-01-20 11:27:56 -0800153private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800154 void Reset();
155
Lee Thomasone4422302012-01-20 17:59:50 -0800156 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800157 NEEDS_FLUSH = 0x100,
158 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800159 };
160
Lee Thomason39ede242012-01-20 11:27:56 -0800161 // After parsing, if *end != 0, it can be set to zero.
162 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800163 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800164 char* end;
165};
166
U-Lama\Lee560bd472011-12-28 19:42:49 -0800167
U-Stream\Leeae25a442012-02-17 17:48:16 -0800168/*
169 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
170 Has a small initial memory pool, so that low or no usage will not
171 cause a call to new/delete
172*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800173template <class T, int INIT>
174class DynArray
175{
176public:
177 DynArray< T, INIT >()
178 {
179 mem = pool;
180 allocated = INIT;
181 size = 0;
182 }
183 ~DynArray()
184 {
185 if ( mem != pool ) {
186 delete mem;
187 }
188 }
189 void Push( T t )
190 {
191 EnsureCapacity( size+1 );
192 mem[size++] = t;
193 }
194
195 T* PushArr( int count )
196 {
197 EnsureCapacity( size+count );
198 T* ret = &mem[size];
199 size += count;
200 return ret;
201 }
202 T Pop() {
203 return mem[--size];
204 }
205 void PopArr( int count )
206 {
207 TIXMLASSERT( size >= count );
208 size -= count;
209 }
210
U-Stream\Leeae25a442012-02-17 17:48:16 -0800211 bool Empty() const { return size == 0; }
212 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
213 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
214 int Size() const { return size; }
215 int Capacity() const { return allocated; }
216 const T* Mem() const { return mem; }
217 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800218
219
220private:
221 void EnsureCapacity( int cap ) {
222 if ( cap > allocated ) {
223 int newAllocated = cap * 2;
224 T* newMem = new T[newAllocated];
225 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
226 if ( mem != pool ) delete [] mem;
227 mem = newMem;
228 allocated = newAllocated;
229 }
230 }
231
232 T* mem;
233 T pool[INIT];
234 int allocated; // objects allocated
235 int size; // number objects in use
236};
237
Lee Thomason50adb4c2012-02-13 15:07:09 -0800238
U-Stream\Leeae25a442012-02-17 17:48:16 -0800239/*
240 Parent virtual class a a pool for fast allocation
241 and deallocation of objects.
242*/
Lee Thomasond1983222012-02-06 08:41:24 -0800243class MemPool
244{
245public:
246 MemPool() {}
247 virtual ~MemPool() {}
248
249 virtual int ItemSize() const = 0;
250 virtual void* Alloc() = 0;
251 virtual void Free( void* ) = 0;
252};
253
Lee Thomason50adb4c2012-02-13 15:07:09 -0800254
U-Stream\Leeae25a442012-02-17 17:48:16 -0800255/*
256 Template child class to create pools of the correct type.
257*/
Lee Thomasond1983222012-02-06 08:41:24 -0800258template< int SIZE >
259class MemPoolT : public MemPool
260{
261public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800262 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800263 ~MemPoolT() {
264 // Delete the blocks.
265 for( int i=0; i<blockPtrs.Size(); ++i ) {
266 delete blockPtrs[i];
267 }
268 }
269
270 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800271 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800272
273 virtual void* Alloc() {
274 if ( !root ) {
275 // Need a new block.
276 Block* block = new Block();
277 blockPtrs.Push( block );
278
279 for( int i=0; i<COUNT-1; ++i ) {
280 block->chunk[i].next = &block->chunk[i+1];
281 }
282 block->chunk[COUNT-1].next = 0;
283 root = block->chunk;
284 }
285 void* result = root;
286 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800287
288 ++currentAllocs;
289 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
290 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800291 return result;
292 }
293 virtual void Free( void* mem ) {
294 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800295 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800296 Chunk* chunk = (Chunk*)mem;
297 memset( chunk, 0xfe, sizeof(Chunk) );
298 chunk->next = root;
299 root = chunk;
300 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800301 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800302 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
303 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800304 }
Lee Thomasond1983222012-02-06 08:41:24 -0800305
306private:
307 enum { COUNT = 1024/SIZE };
308 union Chunk {
309 Chunk* next;
310 char mem[SIZE];
311 };
312 struct Block {
313 Chunk chunk[COUNT];
314 };
315 DynArray< Block*, 10 > blockPtrs;
316 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800317
318 int currentAllocs;
319 int nAllocs;
320 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800321};
322
Lee Thomason2c85a712012-01-31 08:24:24 -0800323
Lee Thomason56bdd022012-02-09 18:16:58 -0800324
325/**
326 Implements the interface to the "Visitor pattern" (see the Accept() method.)
327 If you call the Accept() method, it requires being passed a XMLVisitor
328 class to handle callbacks. For nodes that contain other nodes (Document, Element)
329 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
330 are simply called with Visit().
331
332 If you return 'true' from a Visit method, recursive parsing will continue. If you return
333 false, <b>no children of this node or its sibilings</b> will be Visited.
334
335 All flavors of Visit methods have a default implementation that returns 'true' (continue
336 visiting). You need to only override methods that are interesting to you.
337
338 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
339
340 You should never change the document from a callback.
341
342 @sa XMLNode::Accept()
343*/
344class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800345{
346public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800347 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800348
Lee Thomason56bdd022012-02-09 18:16:58 -0800349 /// Visit a document.
350 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
351 /// Visit a document.
352 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
353
354 /// Visit an element.
355 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
356 /// Visit an element.
357 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
358
359 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800360 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800361 /// Visit a text node
362 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
363 /// Visit a comment node
364 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
365 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800366 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800367};
368
369
U-Stream\Leeae25a442012-02-17 17:48:16 -0800370/*
371 Utility functionality.
372*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800373class XMLUtil
374{
Lee Thomasond1983222012-02-06 08:41:24 -0800375public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800376 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
377 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800378 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
379 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800380
381 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
382 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800383 if ( p == q ) {
384 return true;
385 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800386 while( *p && *q && *p == *q && n<nChar ) {
387 ++p; ++q; ++n;
388 }
389 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
390 return true;
391 }
392 return false;
393 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700394 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800395 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
396 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800397
398 static const char* ReadBOM( const char* p, bool* hasBOM );
399 // p is the starting location,
400 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800401 static const char* GetCharacterRef( const char* p, char* value, int* length );
402 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800403};
404
Lee Thomason5cae8972012-01-24 18:03:07 -0800405
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800406/** XMLNode is a base class for every object that is in the
407 XML Document Object Model (DOM), except XMLAttributes.
408 Nodes have siblings, a parent, and children which can
409 be navigated. A node is always in a XMLDocument.
Lee Thomason3a682622012-03-25 13:19:40 -0700410 The type of a XMLNode can be queried, and it can
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800411 be cast to its more defined type.
412
413 An XMLDocument allocates memory for all its Nodes.
414 When the XMLDocument gets deleted, all its Nodes
415 will also be deleted.
416
417 @verbatim
418 A Document can contain: Element (container or leaf)
419 Comment (leaf)
420 Unknown (leaf)
421 Declaration( leaf )
422
423 An Element can contain: Element (container or leaf)
424 Text (leaf)
425 Attributes (not on tree)
426 Comment (leaf)
427 Unknown (leaf)
428
429 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800430*/
Lee Thomasond1983222012-02-06 08:41:24 -0800431class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800432{
433 friend class XMLDocument;
434 friend class XMLElement;
435public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800436
437 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800438 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800439 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800440 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800441
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800442 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
443 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
444 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
445 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
446 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
447 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800448
Lee Thomason50f97b22012-02-11 16:33:40 -0800449 virtual const XMLElement* ToElement() const { return 0; }
450 virtual const XMLText* ToText() const { return 0; }
451 virtual const XMLComment* ToComment() const { return 0; }
452 virtual const XMLDocument* ToDocument() const { return 0; }
453 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
454 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800455
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800456 /** The meaning of 'value' changes for the specific type.
457 @verbatim
458 Document: empy
459 Element: name of the element
460 Comment: the comment text
461 Unknown: the tag contents
462 Text: the text string
463 @endverbatim
464 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800465 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800466 /** Set the Value of an XML node.
467 @sa Value()
468 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800469 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800470
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800471 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800472 const XMLNode* Parent() const { return parent; }
473 XMLNode* Parent() { return parent; }
474
Lee Thomason50f97b22012-02-11 16:33:40 -0800475 /// Returns true if this node has no children.
476 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800477
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800478 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800479 const XMLNode* FirstChild() const { return firstChild; }
480 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800481 /** Get the first child element, or optionally the first child
482 element with the specified name.
483 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800484 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700485 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800486
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800487 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800488 const XMLNode* LastChild() const { return lastChild; }
489 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800490
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800491 /** Get the last child element or optionally the last child
492 element with the specified name.
493 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800494 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700495 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800496
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800497 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800498 const XMLNode* PreviousSibling() const { return prev; }
499 XMLNode* PreviousSibling() { return prev; }
500
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800501 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800502 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason5ce89412012-03-20 13:23:44 -0700503 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800504
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800505 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800506 const XMLNode* NextSibling() const { return next; }
507 XMLNode* NextSibling() { return next; }
508
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800509 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800510 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700511 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800512
Lee Thomason1ff38e02012-02-14 18:18:16 -0800513 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800514 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800515 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800516 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800517
518 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800519 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800520 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800521 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800522 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800523 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800524 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800525 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800526 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
527
U-Stream\Leeae25a442012-02-17 17:48:16 -0800528 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800529 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800530 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800531 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800532
533 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800534 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800535 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800536 void DeleteChild( XMLNode* node );
537
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800538 /**
539 Make a copy of this node, but not its children.
540 You may pass in a Document pointer that will be
541 the owner of the new Node. If the 'document' is
542 null, then the node returned will be allocated
543 from the current Document. (this->GetDocument())
544
545 Note: if called on a XMLDocument, this will return null.
546 */
547 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
548
549 /**
550 Test if 2 nodes are the same, but don't test children.
551 The 2 nodes do not need to be in the same Document.
552
553 Note: if called on a XMLDocument, this will return false.
554 */
555 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
556
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800557 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
558 XML tree will be conditionally visited and the host will be called back
559 via the TiXmlVisitor interface.
560
561 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
562 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
563 interface versus any other.)
564
565 The interface has been based on ideas from:
566
567 - http://www.saxproject.org/
568 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
569
570 Which are both good references for "visiting".
571
572 An example of using Accept():
573 @verbatim
574 TiXmlPrinter printer;
575 tinyxmlDoc.Accept( &printer );
576 const char* xmlcstr = printer.CStr();
577 @endverbatim
578 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800579 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800580
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800581 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800582 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800583
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800584protected:
585 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800586 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800587 XMLNode( const XMLNode& ); // not supported
588 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800589
Lee Thomason3f57d272012-01-11 15:30:03 -0800590 XMLDocument* document;
591 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800592 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800593
594 XMLNode* firstChild;
595 XMLNode* lastChild;
596
597 XMLNode* prev;
598 XMLNode* next;
599
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800600private:
Lee Thomasond1983222012-02-06 08:41:24 -0800601 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800602 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800603};
604
605
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800606/** XML text.
607
608 Note that a text node can have child element nodes, for example:
609 @verbatim
610 <root>This is <b>bold</b></root>
611 @endverbatim
612
613 A text node can have 2 ways to output the next. "normal" output
614 and CDATA. It will default to the mode it was parsed from the XML file and
615 you generally want to leave it alone, but you can change the output mode with
616 SetCDATA() and query it with CDATA().
617*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800618class XMLText : public XMLNode
619{
Lee Thomason2c85a712012-01-31 08:24:24 -0800620 friend class XMLBase;
621 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800622public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800623 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800624
Lee Thomason751da522012-02-10 08:50:51 -0800625 virtual XMLText* ToText() { return this; }
626 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628 /// Declare whether this should be CDATA or standard text.
Lee Thomason5ce89412012-03-20 13:23:44 -0700629 void SetCData( bool _isCData ) { this->isCData = _isCData; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800630 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800631 bool CData() const { return isCData; }
632
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800633 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800634 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
635 virtual bool ShallowEqual( const XMLNode* compare ) const;
636
Lee Thomason5492a1c2012-01-23 15:32:10 -0800637
638protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800639 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
640 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800641 XMLText( const XMLText& ); // not supported
642 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800643
644private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800645 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800646};
647
648
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800649/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800650class XMLComment : public XMLNode
651{
Lee Thomason2c85a712012-01-31 08:24:24 -0800652 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800653public:
Lee Thomason751da522012-02-10 08:50:51 -0800654 virtual XMLComment* ToComment() { return this; }
655 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800656
Lee Thomason56bdd022012-02-09 18:16:58 -0800657 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800659 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800660 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
661 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800662
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800664 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800665 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800666 XMLComment( const XMLComment& ); // not supported
667 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Lee Thomason3f57d272012-01-11 15:30:03 -0800669private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800670};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800671
672
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800673/** In correct XML the declaration is the first entry in the file.
674 @verbatim
675 <?xml version="1.0" standalone="yes"?>
676 @endverbatim
677
678 TinyXML2 will happily read or write files without a declaration,
679 however.
680
681 The text of the declaration isn't interpreted. It is parsed
682 and written as a string.
683*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800684class XMLDeclaration : public XMLNode
685{
686 friend class XMLDocument;
687public:
688 virtual XMLDeclaration* ToDeclaration() { return this; }
689 virtual const XMLDeclaration* ToDeclaration() const { return this; }
690
691 virtual bool Accept( XMLVisitor* visitor ) const;
692
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800693 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800694 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
695 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800696
697protected:
698 XMLDeclaration( XMLDocument* doc );
699 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800700 XMLDeclaration( const XMLDeclaration& ); // not supported
701 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800702};
703
704
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800705/** Any tag that tinyXml doesn't recognize is saved as an
706 unknown. It is a tag of text, but should not be modified.
707 It will be written back to the XML, unchanged, when the file
708 is saved.
709
710 DTD tags get thrown into TiXmlUnknowns.
711*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800712class XMLUnknown : public XMLNode
713{
714 friend class XMLDocument;
715public:
716 virtual XMLUnknown* ToUnknown() { return this; }
717 virtual const XMLUnknown* ToUnknown() const { return this; }
718
719 virtual bool Accept( XMLVisitor* visitor ) const;
720
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800721 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800722 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
723 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800724
725protected:
726 XMLUnknown( XMLDocument* doc );
727 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800728 XMLUnknown( const XMLUnknown& ); // not supported
729 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800730};
731
732
Lee Thomason1ff38e02012-02-14 18:18:16 -0800733enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800734 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800735 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800736
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700737 XML_NO_ATTRIBUTE,
738 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800739
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700740 XML_ERROR_FILE_NOT_FOUND,
Lee Thomason7f7b1622012-03-24 12:49:03 -0700741 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700742 XML_ERROR_ELEMENT_MISMATCH,
743 XML_ERROR_PARSING_ELEMENT,
744 XML_ERROR_PARSING_ATTRIBUTE,
745 XML_ERROR_IDENTIFYING_TAG,
746 XML_ERROR_PARSING_TEXT,
747 XML_ERROR_PARSING_CDATA,
748 XML_ERROR_PARSING_COMMENT,
749 XML_ERROR_PARSING_DECLARATION,
750 XML_ERROR_PARSING_UNKNOWN,
751 XML_ERROR_EMPTY_DOCUMENT,
752 XML_ERROR_MISMATCHED_ELEMENT,
753 XML_ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800754};
755
756
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800757/** An attribute is a name-value pair. Elements have an arbitrary
758 number of attributes, each with a unique name.
759
760 @note The attributes are not XMLNodes. You may only query the
761 Next() attribute in a list.
762*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800763class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800764{
765 friend class XMLElement;
766public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800767 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
768 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
769 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800770
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800771 /** IntAttribute interprets the attribute as an integer, and returns the value.
772 If the value isn't an integer, 0 will be returned. There is no error checking;
773 use QueryIntAttribute() if you need error checking.
774 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800775 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800776 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800777 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800778 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800779 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800780 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800782 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800783 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800784
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800785 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
786 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700787 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800789 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800790 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800791 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800793 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800794 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800795 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800796 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800797 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800798
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800799 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800800 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800801 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800802 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800803 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800804 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800805 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800806 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800807 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800808 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800809 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800810 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800811
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800812private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800813 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800814
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800815 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800816 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800817 XMLAttribute( const XMLAttribute& ); // not supported
818 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800819 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800820
Lee Thomason6f381b72012-03-02 12:59:39 -0800821 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800822
Lee Thomason751da522012-02-10 08:50:51 -0800823 mutable StrPair name;
824 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800825 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800826 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800827};
828
829
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800830/** The element is a container class. It has a value, the element name,
831 and can contain other elements, text, comments, and unknowns.
832 Elements also contain an arbitrary number of attributes.
833*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800834class XMLElement : public XMLNode
835{
Lee Thomason2c85a712012-01-31 08:24:24 -0800836 friend class XMLBase;
837 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800838public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800839 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800840 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800841 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800842 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800843
Lee Thomason751da522012-02-10 08:50:51 -0800844 virtual XMLElement* ToElement() { return this; }
845 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800846 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800847
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800848 /** Given an attribute name, Attribute() returns the value
Lee Thomason92258152012-03-24 13:05:39 -0700849 for the attribute of that name, or null if none
850 exists. For example:
851
852 @verbatim
853 const char* value = ele->Attribute( "foo" );
854 @endverbatim
855
856 The 'value' parameter is normally null. However, if specified,
857 the attribute will only be returned if the 'name' and 'value'
858 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700859
860 @verbatim
861 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
862 @endverbatim
863
864 rather than:
865 @verbatim
866 if ( ele->Attribute( "foo" ) ) {
867 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
868 }
869 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800870 */
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700871 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800872
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800873 /** Given an attribute name, IntAttribute() returns the value
874 of the attribute interpreted as an integer. 0 will be
875 returned if there is an error. For a method with error
876 checking, see QueryIntAttribute()
877 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800878 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800879 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800880 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800881 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800882 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800883 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800884 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800885 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800886 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
887
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800888 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700889 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
890 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800891 doesn't exist. If successful, the result of the conversion
892 will be written to 'value'. If not successful, nothing will
893 be written to 'value'. This allows you to provide default
894 value:
895
896 @verbatim
897 int value = 10;
898 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
899 @endverbatim
900 */
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700901 int QueryIntAttribute( const char* name, int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryIntValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800902 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700903 int QueryUnsignedAttribute( const char* name, unsigned int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryUnsignedValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800904 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700905 int QueryBoolAttribute( const char* name, bool* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryBoolValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800906 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700907 int QueryDoubleAttribute( const char* name, double* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryDoubleValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800908 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700909 int QueryFloatAttribute( const char* name, float* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryFloatValue( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800910
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800911 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700912 void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800913 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700914 void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800915 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700916 void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800917 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700918 void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800919 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700920 void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800921
U-Stream\Leeae25a442012-02-17 17:48:16 -0800922 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800923 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800924 */
925 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800926
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800927 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800928 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800929 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800930 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800931
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800932 /** Convenience function for easy access to the text inside an element. Although easy
933 and concise, GetText() is limited compared to getting the TiXmlText child
934 and accessing it directly.
935
936 If the first child of 'this' is a TiXmlText, the GetText()
937 returns the character string of the Text node, else null is returned.
938
939 This is a convenient method for getting the text of simple contained text:
940 @verbatim
941 <foo>This is text</foo>
942 const char* str = fooElement->GetText();
943 @endverbatim
944
945 'str' will be a pointer to "This is text".
946
947 Note that this function can be misleading. If the element foo was created from
948 this XML:
949 @verbatim
950 <foo><b>This is text</b></foo>
951 @endverbatim
952
953 then the value of str would be null. The first child node isn't a text node, it is
954 another element. From this XML:
955 @verbatim
956 <foo>This is <b>text</b></foo>
957 @endverbatim
958 GetText() will return "This is ".
959 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800960 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800961
Lee Thomason2c85a712012-01-31 08:24:24 -0800962 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963 enum {
964 OPEN, // <foo>
965 CLOSED, // <foo/>
966 CLOSING // </foo>
967 };
968 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800969 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800970 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
971 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800972
Lee Thomason50adb4c2012-02-13 15:07:09 -0800973private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800974 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800975 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800976 XMLElement( const XMLElement& ); // not supported
977 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800978
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800979 XMLAttribute* FindAttribute( const char* name );
980 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800981 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800982 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800983
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800984 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800985 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800986};
987
988
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800989/** A document binds together all the functionality.
990 It can be saved, loaded, and printed to the screen.
991 All Nodes are connected and allocated to a Document.
992 If the Document is deleted, all its Nodes are also deleted.
993*/
Lee Thomason67d61312012-01-24 16:01:51 -0800994class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800995{
Lee Thomasond1983222012-02-06 08:41:24 -0800996 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800997public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800998 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -0800999 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -08001000 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001001
Lee Thomason751da522012-02-10 08:50:51 -08001002 virtual XMLDocument* ToDocument() { return this; }
1003 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -08001004
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001005 /**
1006 Parse an XML file from a character string.
1007 Returns XML_NO_ERROR (0) on success, or
1008 an errorID.
1009 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001010 int Parse( const char* xml );
Lee Thomasond11cd162012-04-12 08:35:36 -07001011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001012 /**
1013 Load an XML file from disk.
1014 Returns XML_NO_ERROR (0) on success, or
1015 an errorID.
Lee Thomasond11cd162012-04-12 08:35:36 -07001016 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001017 int LoadFile( const char* filename );
Lee Thomasond11cd162012-04-12 08:35:36 -07001018
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001019 /**
1020 Load an XML file from disk. You are responsible
1021 for providing and closing the FILE*.
1022
1023 Returns XML_NO_ERROR (0) on success, or
1024 an errorID.
Lee Thomasond11cd162012-04-12 08:35:36 -07001025 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001026 int LoadFile( FILE* );
Lee Thomasond11cd162012-04-12 08:35:36 -07001027
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001028 /**
1029 Save the XML file to disk.
Ken Miller81da1fb2012-04-09 23:32:26 -05001030 Returns XML_NO_ERROR (0) on success, or
1031 an errorID.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001032 */
Ken Miller81da1fb2012-04-09 23:32:26 -05001033 int SaveFile( const char* filename );
Lee Thomasond11cd162012-04-12 08:35:36 -07001034
Ken Miller81da1fb2012-04-09 23:32:26 -05001035 /**
1036 Save the XML file to disk. You are responsible
1037 for providing and closing the FILE*.
1038
1039 Returns XML_NO_ERROR (0) on success, or
1040 an errorID.
1041 */
1042 int SaveFile( FILE* );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001043
Lee Thomason6f381b72012-03-02 12:59:39 -08001044 bool ProcessEntities() const { return processEntities; }
1045
1046 /**
1047 Returns true if this document has a leading Byte Order Mark of UTF8.
1048 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001049 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001050
1051 /** Return the root element of DOM. Equivalent to FirstChildElement().
1052 To get the first node, use FirstChild().
1053 */
Lee Thomasond6277762012-02-22 16:00:12 -08001054 XMLElement* RootElement() { return FirstChildElement(); }
1055 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001056
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001057 /** Print the Document. If the Printer is not provided, it will
1058 print to stdout. If you provide Printer, this can print to a file:
1059 @verbatim
1060 XMLPrinter printer( fp );
1061 doc.Print( &printer );
1062 @endverbatim
1063
1064 Or you can use a printer to print to memory:
1065 @verbatim
1066 XMLPrinter printer;
1067 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001068 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001069 @endverbatim
1070 */
1071 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001072 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001073
Lee Thomason1ff38e02012-02-14 18:18:16 -08001074 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001075 Create a new Element associated with
1076 this Document. The memory for the Element
1077 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001078 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001079 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001080 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001081 Create a new Comment associated with
1082 this Document. The memory for the Comment
1083 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001084 */
1085 XMLComment* NewComment( const char* comment );
1086 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001087 Create a new Text associated with
1088 this Document. The memory for the Text
1089 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001090 */
1091 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092 /**
1093 Create a new Declaration associated with
1094 this Document. The memory for the object
1095 is managed by the Document.
1096 */
1097 XMLDeclaration* NewDeclaration( const char* text );
1098 /**
1099 Create a new Unknown associated with
1100 this Document. The memory for the object
1101 is managed by the Document.
1102 */
1103 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001104
U-Stream\Leeae25a442012-02-17 17:48:16 -08001105 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001106 Delete a node associated with this documented.
1107 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001108 */
1109 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1110
Lee Thomason67d61312012-01-24 16:01:51 -08001111 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001112
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001113 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001114 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001115 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001116 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001117 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001118 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001119 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001120 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001121 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001122 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001123
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001124 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001125 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001126
Lee Thomason6f381b72012-03-02 12:59:39 -08001127 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1128 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001129
Lee Thomason3f57d272012-01-11 15:30:03 -08001130private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001131 XMLDocument( const XMLDocument& ); // not supported
1132 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001133 void InitDocument();
1134
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001135 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001136 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001137 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001138 const char* errorStr1;
1139 const char* errorStr2;
1140 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001141
1142 MemPoolT< sizeof(XMLElement) > elementPool;
1143 MemPoolT< sizeof(XMLAttribute) > attributePool;
1144 MemPoolT< sizeof(XMLText) > textPool;
1145 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001146};
1147
Lee Thomason7c913cd2012-01-26 18:32:34 -08001148
Lee Thomason3ffdd392012-03-28 17:27:55 -07001149/**
1150 A XMLHandle is a class that wraps a node pointer with null checks; this is
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001151 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
Lee Thomason3ffdd392012-03-28 17:27:55 -07001152 DOM structure. It is a separate utility class.
1153
1154 Take an example:
1155 @verbatim
1156 <Document>
1157 <Element attributeA = "valueA">
1158 <Child attributeB = "value1" />
1159 <Child attributeB = "value2" />
1160 </Element>
1161 <Document>
1162 @endverbatim
1163
1164 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
1165 easy to write a *lot* of code that looks like:
1166
1167 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001168 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001169 if ( root )
1170 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001171 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001172 if ( element )
1173 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001174 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001175 if ( child )
1176 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001177 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001178 if ( child2 )
1179 {
1180 // Finally do something useful.
1181 @endverbatim
1182
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001183 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
1184 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07001185 and correct to use:
1186
1187 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07001188 XMLHandle docHandle( &document );
1189 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07001190 if ( child2 )
1191 {
1192 // do something useful
1193 @endverbatim
1194
1195 Which is MUCH more concise and useful.
1196
1197 It is also safe to copy handles - internally they are nothing more than node pointers.
1198 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001199 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001200 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001201
1202 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001203*/
1204class XMLHandle
1205{
1206public:
1207 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
Lee Thomason8b899812012-04-04 15:58:16 -07001208 XMLHandle( XMLNode* _node ) { node = _node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001209 /// Create a handle from a node.
Lee Thomason8b899812012-04-04 15:58:16 -07001210 XMLHandle( XMLNode& _node ) { node = &_node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001211 /// Copy constructor
Lee Thomason8b899812012-04-04 15:58:16 -07001212 XMLHandle( const XMLHandle& ref ) { node = ref.node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001213 /// Assignment
Lee Thomason8b899812012-04-04 15:58:16 -07001214 XMLHandle operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001215
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001216 /// Get the first child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001217 XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001218 /// Get the first child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001219 XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001220 /// Get the last child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001221 XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001222 /// Get the last child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001223 XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001224 /// Get the previous sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001225 XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001226 /// Get the previous sibling element of this handle.
Lee Thomason5708f812012-03-28 17:46:41 -07001227 XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001228 /// Get the next sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001229 XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001230 /// Get the next sibling element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001231 XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001232
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001233 /// Safe cast to XMLNode. This can return null.
Lee Thomason8b899812012-04-04 15:58:16 -07001234 XMLNode* ToNode() { return node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001235 /// Safe cast to XMLElement. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001236 XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001237 /// Safe cast to XMLText. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001238 XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001239 /// Safe cast to XMLUnknown. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001240 XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001241 /// Safe cast to XMLDeclaration. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001242 XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001243
1244private:
1245 XMLNode* node;
1246};
1247
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001248
1249/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001250 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1251 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07001252*/
1253class XMLConstHandle
1254{
1255public:
1256 XMLConstHandle( const XMLNode* _node ) { node = _node; }
1257 XMLConstHandle( const XMLNode& _node ) { node = &_node; }
1258 XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
1259
1260 XMLConstHandle operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
1261
1262 const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
1263 const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
1264 const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
1265 const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
1266 const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
1267 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
1268 const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
1269 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
1270
1271
1272 const XMLNode* ToNode() const { return node; }
1273 const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
1274 const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
1275 const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001276 const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
1277
Lee Thomason5cae8972012-01-24 18:03:07 -08001278private:
Lee Thomason8b899812012-04-04 15:58:16 -07001279 const XMLNode* node;
Lee Thomason56bdd022012-02-09 18:16:58 -08001280};
Lee Thomason6f381b72012-03-02 12:59:39 -08001281
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001282
1283/**
1284 Printing functionality. The XMLPrinter gives you more
1285 options than the XMLDocument::Print() method.
1286
1287 It can:
1288 -# Print to memory.
1289 -# Print to a file you provide
1290 -# Print XML without a XMLDocument.
1291
1292 Print to Memory
1293
1294 @verbatim
1295 XMLPrinter printer;
1296 doc->Print( &printer );
1297 SomeFunctior( printer.CStr() );
1298 @endverbatim
1299
1300 Print to a File
1301
1302 You provide the file pointer.
1303 @verbatim
1304 XMLPrinter printer( fp );
1305 doc.Print( &printer );
1306 @endverbatim
1307
1308 Print without a XMLDocument
1309
1310 When loading, an XML parser is very useful. However, sometimes
1311 when saving, it just gets in the way. The code is often set up
1312 for streaming, and constructing the DOM is just overhead.
1313
1314 The Printer supports the streaming case. The following code
1315 prints out a trivially simple XML file without ever creating
1316 an XML document.
1317
1318 @verbatim
1319 XMLPrinter printer( fp );
1320 printer.OpenElement( "foo" );
1321 printer.PushAttribute( "foo", "bar" );
1322 printer.CloseElement();
1323 @endverbatim
1324*/
1325class XMLPrinter : public XMLVisitor
1326{
1327public:
1328 /** Construct the printer. If the FILE* is specified,
1329 this will print to the FILE. Else it will print
1330 to memory, and the result is available in CStr()
1331 */
1332 XMLPrinter( FILE* file=0 );
1333 ~XMLPrinter() {}
1334
1335 /** If streaming, write the BOM and declaration. */
1336 void PushHeader( bool writeBOM, bool writeDeclaration );
1337 /** If streaming, start writing an element.
1338 The element must be closed with CloseElement()
1339 */
1340 void OpenElement( const char* name );
1341 /// If streaming, add an attribute to an open element.
1342 void PushAttribute( const char* name, const char* value );
1343 void PushAttribute( const char* name, int value );
1344 void PushAttribute( const char* name, unsigned value );
1345 void PushAttribute( const char* name, bool value );
1346 void PushAttribute( const char* name, double value );
1347 /// If streaming, close the Element.
1348 void CloseElement();
1349
1350 /// Add a text node.
1351 void PushText( const char* text, bool cdata=false );
1352 /// Add a comment
1353 void PushComment( const char* comment );
1354
1355 void PushDeclaration( const char* value );
1356 void PushUnknown( const char* value );
1357
1358 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
1359 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1360
1361 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1362 virtual bool VisitExit( const XMLElement& element );
1363
1364 virtual bool Visit( const XMLText& text );
1365 virtual bool Visit( const XMLComment& comment );
1366 virtual bool Visit( const XMLDeclaration& declaration );
1367 virtual bool Visit( const XMLUnknown& unknown );
1368
1369 /**
1370 If in print to memory mode, return a pointer to
1371 the XML file in memory.
1372 */
1373 const char* CStr() const { return buffer.Mem(); }
1374
1375private:
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001376 void SealElement();
1377 void PrintSpace( int depth );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001378 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
1379 void Print( const char* format, ... );
1380
1381 bool elementJustOpened;
1382 bool firstElement;
1383 FILE* fp;
1384 int depth;
1385 int textDepth;
1386 bool processEntities;
1387
1388 enum {
1389 ENTITY_RANGE = 64,
1390 BUF_SIZE = 200
1391 };
1392 bool entityFlag[ENTITY_RANGE];
1393 bool restrictedEntityFlag[ENTITY_RANGE];
1394
1395 DynArray< const char*, 10 > stack;
1396 DynArray< char, 20 > buffer, accumulator;
1397};
1398
1399
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001400} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001401
1402
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001403#endif // TINYXML2_INCLUDED