blob: 0acf9d885d7d3186e79199365507ce02ff7d4822 [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>
32#else
33 // Not completely sure all the interesting systems
34 // can handle the new headers; can switch this if
35 // there is an include problem.
36 #include <limits.h>
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <memory.h> // Needed by mac.
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -070040#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080041
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070042
Lee Thomason7d00b9a2012-02-27 17:54:22 -080043/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080044 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080045 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080046*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080047/*
48 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
49*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080050
U-Lama\Lee4cee6112011-12-31 14:58:18 -080051#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
52 #ifndef DEBUG
53 #define DEBUG
54 #endif
55#endif
56
57
58#if defined(DEBUG)
59 #if defined(_MSC_VER)
Guillermo A. Amaral68b0c872012-03-24 11:07:19 -070060 #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
U-Lama\Lee4cee6112011-12-31 14:58:18 -080061 #elif defined (ANDROID_NDK)
62 #include <android/log.h>
63 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
64 #else
65 #include <assert.h>
66 #define TIXMLASSERT assert
67 #endif
68#else
69 #define TIXMLASSERT( x ) {}
70#endif
71
U-Lama\Leee13c3e62011-12-28 14:36:55 -080072
Lee Thomason1a1d4a72012-02-15 09:09:25 -080073// Deprecated library function hell. Compilers want to use the
74// new safe versions. This probably doesn't fully address the problem,
75// but it gets closer. There are too many compilers for me to fully
76// test. If you get compilation troubles, undefine TIXML_SAFE
77
78#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
79 // Microsoft visual studio, version 2005 and higher.
80 #define TIXML_SNPRINTF _snprintf_s
81 #define TIXML_SSCANF sscanf_s
82#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
83 // Microsoft visual studio, version 6 and higher.
84 //#pragma message( "Using _sn* functions." )
85 #define TIXML_SNPRINTF _snprintf
86 #define TIXML_SSCANF sscanf
87#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080088 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080089 //#warning( "Using sn* functions." )
90 #define TIXML_SNPRINTF snprintf
91 #define TIXML_SSCANF sscanf
92#else
93 #define TIXML_SNPRINTF snprintf
94 #define TIXML_SSCANF sscanf
95#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080096
Lee Thomason7f7b1622012-03-24 12:49:03 -070097static const int TIXML2_MAJOR_VERSION = 0;
98static const int TIXML2_MINOR_VERSION = 9;
Lee Thomason (grinliz)c8678e22012-04-04 12:39:53 -070099static const int TIXML2_PATCH_VERSION = 3;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800100
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800101namespace tinyxml2
102{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800103class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800104class XMLElement;
105class XMLAttribute;
106class XMLComment;
107class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800108class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800109class XMLDeclaration;
110class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800111
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800112class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800113
U-Stream\Leeae25a442012-02-17 17:48:16 -0800114/*
115 A class that wraps strings. Normally stores the start and end
116 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800117 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800118 manage) a traditional char[]
119*/
Lee Thomason39ede242012-01-20 11:27:56 -0800120class StrPair
121{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800122public:
Lee Thomason39ede242012-01-20 11:27:56 -0800123 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800124 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800125 NEEDS_NEWLINE_NORMALIZATION = 0x02,
126
127 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800128 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800129 ATTRIBUTE_NAME = 0,
130 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800131 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700132 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800133 };
134
135 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136 ~StrPair();
137
Lee Thomason5ce89412012-03-20 13:23:44 -0700138 void Set( char* _start, char* _end, int _flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800139 Reset();
Lee Thomason5ce89412012-03-20 13:23:44 -0700140 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800141 }
142 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800143 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800144
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700145 void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146 void SetStr( const char* str, int flags=0 );
147
Lee Thomason56bdd022012-02-09 18:16:58 -0800148 char* ParseText( char* in, const char* endTag, int strFlags );
149 char* ParseName( char* in );
150
Lee Thomason2c85a712012-01-31 08:24:24 -0800151
Lee Thomason39ede242012-01-20 11:27:56 -0800152private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800153 void Reset();
154
Lee Thomasone4422302012-01-20 17:59:50 -0800155 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800156 NEEDS_FLUSH = 0x100,
157 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800158 };
159
Lee Thomason39ede242012-01-20 11:27:56 -0800160 // After parsing, if *end != 0, it can be set to zero.
161 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800162 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800163 char* end;
164};
165
U-Lama\Lee560bd472011-12-28 19:42:49 -0800166
U-Stream\Leeae25a442012-02-17 17:48:16 -0800167/*
168 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
169 Has a small initial memory pool, so that low or no usage will not
170 cause a call to new/delete
171*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800172template <class T, int INIT>
173class DynArray
174{
175public:
176 DynArray< T, INIT >()
177 {
178 mem = pool;
179 allocated = INIT;
180 size = 0;
181 }
182 ~DynArray()
183 {
184 if ( mem != pool ) {
185 delete mem;
186 }
187 }
188 void Push( T t )
189 {
190 EnsureCapacity( size+1 );
191 mem[size++] = t;
192 }
193
194 T* PushArr( int count )
195 {
196 EnsureCapacity( size+count );
197 T* ret = &mem[size];
198 size += count;
199 return ret;
200 }
201 T Pop() {
202 return mem[--size];
203 }
204 void PopArr( int count )
205 {
206 TIXMLASSERT( size >= count );
207 size -= count;
208 }
209
U-Stream\Leeae25a442012-02-17 17:48:16 -0800210 bool Empty() const { return size == 0; }
211 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
212 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
213 int Size() const { return size; }
214 int Capacity() const { return allocated; }
215 const T* Mem() const { return mem; }
216 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800217
218
219private:
220 void EnsureCapacity( int cap ) {
221 if ( cap > allocated ) {
222 int newAllocated = cap * 2;
223 T* newMem = new T[newAllocated];
224 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
225 if ( mem != pool ) delete [] mem;
226 mem = newMem;
227 allocated = newAllocated;
228 }
229 }
230
231 T* mem;
232 T pool[INIT];
233 int allocated; // objects allocated
234 int size; // number objects in use
235};
236
Lee Thomason50adb4c2012-02-13 15:07:09 -0800237
U-Stream\Leeae25a442012-02-17 17:48:16 -0800238/*
239 Parent virtual class a a pool for fast allocation
240 and deallocation of objects.
241*/
Lee Thomasond1983222012-02-06 08:41:24 -0800242class MemPool
243{
244public:
245 MemPool() {}
246 virtual ~MemPool() {}
247
248 virtual int ItemSize() const = 0;
249 virtual void* Alloc() = 0;
250 virtual void Free( void* ) = 0;
251};
252
Lee Thomason50adb4c2012-02-13 15:07:09 -0800253
U-Stream\Leeae25a442012-02-17 17:48:16 -0800254/*
255 Template child class to create pools of the correct type.
256*/
Lee Thomasond1983222012-02-06 08:41:24 -0800257template< int SIZE >
258class MemPoolT : public MemPool
259{
260public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800261 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800262 ~MemPoolT() {
263 // Delete the blocks.
264 for( int i=0; i<blockPtrs.Size(); ++i ) {
265 delete blockPtrs[i];
266 }
267 }
268
269 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800270 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800271
272 virtual void* Alloc() {
273 if ( !root ) {
274 // Need a new block.
275 Block* block = new Block();
276 blockPtrs.Push( block );
277
278 for( int i=0; i<COUNT-1; ++i ) {
279 block->chunk[i].next = &block->chunk[i+1];
280 }
281 block->chunk[COUNT-1].next = 0;
282 root = block->chunk;
283 }
284 void* result = root;
285 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800286
287 ++currentAllocs;
288 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
289 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800290 return result;
291 }
292 virtual void Free( void* mem ) {
293 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800294 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800295 Chunk* chunk = (Chunk*)mem;
296 memset( chunk, 0xfe, sizeof(Chunk) );
297 chunk->next = root;
298 root = chunk;
299 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800300 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800301 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
302 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800303 }
Lee Thomasond1983222012-02-06 08:41:24 -0800304
305private:
306 enum { COUNT = 1024/SIZE };
307 union Chunk {
308 Chunk* next;
309 char mem[SIZE];
310 };
311 struct Block {
312 Chunk chunk[COUNT];
313 };
314 DynArray< Block*, 10 > blockPtrs;
315 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800316
317 int currentAllocs;
318 int nAllocs;
319 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800320};
321
Lee Thomason2c85a712012-01-31 08:24:24 -0800322
Lee Thomason56bdd022012-02-09 18:16:58 -0800323
324/**
325 Implements the interface to the "Visitor pattern" (see the Accept() method.)
326 If you call the Accept() method, it requires being passed a XMLVisitor
327 class to handle callbacks. For nodes that contain other nodes (Document, Element)
328 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
329 are simply called with Visit().
330
331 If you return 'true' from a Visit method, recursive parsing will continue. If you return
332 false, <b>no children of this node or its sibilings</b> will be Visited.
333
334 All flavors of Visit methods have a default implementation that returns 'true' (continue
335 visiting). You need to only override methods that are interesting to you.
336
337 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
338
339 You should never change the document from a callback.
340
341 @sa XMLNode::Accept()
342*/
343class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800344{
345public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800346 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800347
Lee Thomason56bdd022012-02-09 18:16:58 -0800348 /// Visit a document.
349 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
350 /// Visit a document.
351 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
352
353 /// Visit an element.
354 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
355 /// Visit an element.
356 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
357
358 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800359 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800360 /// Visit a text node
361 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
362 /// Visit a comment node
363 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
364 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800365 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800366};
367
368
U-Stream\Leeae25a442012-02-17 17:48:16 -0800369/*
370 Utility functionality.
371*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800372class XMLUtil
373{
Lee Thomasond1983222012-02-06 08:41:24 -0800374public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800375 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
376 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800377 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
378 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800379
380 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
381 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800382 if ( p == q ) {
383 return true;
384 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800385 while( *p && *q && *p == *q && n<nChar ) {
386 ++p; ++q; ++n;
387 }
388 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
389 return true;
390 }
391 return false;
392 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700393 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800394 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
395 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800396
397 static const char* ReadBOM( const char* p, bool* hasBOM );
398 // p is the starting location,
399 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800400 static const char* GetCharacterRef( const char* p, char* value, int* length );
401 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800402};
403
Lee Thomason5cae8972012-01-24 18:03:07 -0800404
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800405/** XMLNode is a base class for every object that is in the
406 XML Document Object Model (DOM), except XMLAttributes.
407 Nodes have siblings, a parent, and children which can
408 be navigated. A node is always in a XMLDocument.
Lee Thomason3a682622012-03-25 13:19:40 -0700409 The type of a XMLNode can be queried, and it can
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800410 be cast to its more defined type.
411
412 An XMLDocument allocates memory for all its Nodes.
413 When the XMLDocument gets deleted, all its Nodes
414 will also be deleted.
415
416 @verbatim
417 A Document can contain: Element (container or leaf)
418 Comment (leaf)
419 Unknown (leaf)
420 Declaration( leaf )
421
422 An Element can contain: Element (container or leaf)
423 Text (leaf)
424 Attributes (not on tree)
425 Comment (leaf)
426 Unknown (leaf)
427
428 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800429*/
Lee Thomasond1983222012-02-06 08:41:24 -0800430class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800431{
432 friend class XMLDocument;
433 friend class XMLElement;
434public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800435
436 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800437 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800438 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800439 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800440
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800441 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
442 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
443 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
444 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
445 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
446 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800447
Lee Thomason50f97b22012-02-11 16:33:40 -0800448 virtual const XMLElement* ToElement() const { return 0; }
449 virtual const XMLText* ToText() const { return 0; }
450 virtual const XMLComment* ToComment() const { return 0; }
451 virtual const XMLDocument* ToDocument() const { return 0; }
452 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
453 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800454
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800455 /** The meaning of 'value' changes for the specific type.
456 @verbatim
457 Document: empy
458 Element: name of the element
459 Comment: the comment text
460 Unknown: the tag contents
461 Text: the text string
462 @endverbatim
463 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800464 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800465 /** Set the Value of an XML node.
466 @sa Value()
467 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800468 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800470 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800471 const XMLNode* Parent() const { return parent; }
472 XMLNode* Parent() { return parent; }
473
Lee Thomason50f97b22012-02-11 16:33:40 -0800474 /// Returns true if this node has no children.
475 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800476
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800477 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800478 const XMLNode* FirstChild() const { return firstChild; }
479 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800480 /** Get the first child element, or optionally the first child
481 element with the specified name.
482 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800483 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700484 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800485
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800486 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800487 const XMLNode* LastChild() const { return lastChild; }
488 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800489
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800490 /** Get the last child element or optionally the last child
491 element with the specified name.
492 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800493 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700494 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800495
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800496 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800497 const XMLNode* PreviousSibling() const { return prev; }
498 XMLNode* PreviousSibling() { return prev; }
499
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800500 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800501 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason5ce89412012-03-20 13:23:44 -0700502 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800503
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800504 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800505 const XMLNode* NextSibling() const { return next; }
506 XMLNode* NextSibling() { return next; }
507
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800508 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800509 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700510 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800511
Lee Thomason1ff38e02012-02-14 18:18:16 -0800512 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800513 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800514 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800515 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800516
517 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800518 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800519 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800520 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800521 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800522 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800523 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800524 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800525 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
526
U-Stream\Leeae25a442012-02-17 17:48:16 -0800527 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800528 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800529 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800530 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800531
532 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800533 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800534 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800535 void DeleteChild( XMLNode* node );
536
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800537 /**
538 Make a copy of this node, but not its children.
539 You may pass in a Document pointer that will be
540 the owner of the new Node. If the 'document' is
541 null, then the node returned will be allocated
542 from the current Document. (this->GetDocument())
543
544 Note: if called on a XMLDocument, this will return null.
545 */
546 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
547
548 /**
549 Test if 2 nodes are the same, but don't test children.
550 The 2 nodes do not need to be in the same Document.
551
552 Note: if called on a XMLDocument, this will return false.
553 */
554 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
555
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800556 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
557 XML tree will be conditionally visited and the host will be called back
558 via the TiXmlVisitor interface.
559
560 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
561 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
562 interface versus any other.)
563
564 The interface has been based on ideas from:
565
566 - http://www.saxproject.org/
567 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
568
569 Which are both good references for "visiting".
570
571 An example of using Accept():
572 @verbatim
573 TiXmlPrinter printer;
574 tinyxmlDoc.Accept( &printer );
575 const char* xmlcstr = printer.CStr();
576 @endverbatim
577 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800578 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800579
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800580 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800581 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800582
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800583protected:
584 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800585 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800586 XMLNode( const XMLNode& ); // not supported
587 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800588
Lee Thomason3f57d272012-01-11 15:30:03 -0800589 XMLDocument* document;
590 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800591 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800592
593 XMLNode* firstChild;
594 XMLNode* lastChild;
595
596 XMLNode* prev;
597 XMLNode* next;
598
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800599private:
Lee Thomasond1983222012-02-06 08:41:24 -0800600 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800601 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800602};
603
604
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800605/** XML text.
606
607 Note that a text node can have child element nodes, for example:
608 @verbatim
609 <root>This is <b>bold</b></root>
610 @endverbatim
611
612 A text node can have 2 ways to output the next. "normal" output
613 and CDATA. It will default to the mode it was parsed from the XML file and
614 you generally want to leave it alone, but you can change the output mode with
615 SetCDATA() and query it with CDATA().
616*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800617class XMLText : public XMLNode
618{
Lee Thomason2c85a712012-01-31 08:24:24 -0800619 friend class XMLBase;
620 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800621public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800622 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800623
Lee Thomason751da522012-02-10 08:50:51 -0800624 virtual XMLText* ToText() { return this; }
625 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800626
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800627 /// Declare whether this should be CDATA or standard text.
Lee Thomason5ce89412012-03-20 13:23:44 -0700628 void SetCData( bool _isCData ) { this->isCData = _isCData; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800629 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800630 bool CData() const { return isCData; }
631
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800632 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800633 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
634 virtual bool ShallowEqual( const XMLNode* compare ) const;
635
Lee Thomason5492a1c2012-01-23 15:32:10 -0800636
637protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800638 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
639 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800640 XMLText( const XMLText& ); // not supported
641 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800642
643private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800644 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800645};
646
647
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800648/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800649class XMLComment : public XMLNode
650{
Lee Thomason2c85a712012-01-31 08:24:24 -0800651 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800652public:
Lee Thomason751da522012-02-10 08:50:51 -0800653 virtual XMLComment* ToComment() { return this; }
654 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800655
Lee Thomason56bdd022012-02-09 18:16:58 -0800656 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800658 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800659 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
660 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800661
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800662protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800663 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800664 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800665 XMLComment( const XMLComment& ); // not supported
666 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason3f57d272012-01-11 15:30:03 -0800668private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800669};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800670
671
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800672/** In correct XML the declaration is the first entry in the file.
673 @verbatim
674 <?xml version="1.0" standalone="yes"?>
675 @endverbatim
676
677 TinyXML2 will happily read or write files without a declaration,
678 however.
679
680 The text of the declaration isn't interpreted. It is parsed
681 and written as a string.
682*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800683class XMLDeclaration : public XMLNode
684{
685 friend class XMLDocument;
686public:
687 virtual XMLDeclaration* ToDeclaration() { return this; }
688 virtual const XMLDeclaration* ToDeclaration() const { return this; }
689
690 virtual bool Accept( XMLVisitor* visitor ) const;
691
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800692 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800693 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
694 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800695
696protected:
697 XMLDeclaration( XMLDocument* doc );
698 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800699 XMLDeclaration( const XMLDeclaration& ); // not supported
700 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800701};
702
703
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800704/** Any tag that tinyXml doesn't recognize is saved as an
705 unknown. It is a tag of text, but should not be modified.
706 It will be written back to the XML, unchanged, when the file
707 is saved.
708
709 DTD tags get thrown into TiXmlUnknowns.
710*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800711class XMLUnknown : public XMLNode
712{
713 friend class XMLDocument;
714public:
715 virtual XMLUnknown* ToUnknown() { return this; }
716 virtual const XMLUnknown* ToUnknown() const { return this; }
717
718 virtual bool Accept( XMLVisitor* visitor ) const;
719
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800720 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800721 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
722 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800723
724protected:
725 XMLUnknown( XMLDocument* doc );
726 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800727 XMLUnknown( const XMLUnknown& ); // not supported
728 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800729};
730
731
Lee Thomason1ff38e02012-02-14 18:18:16 -0800732enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800733 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800734 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800735
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700736 XML_NO_ATTRIBUTE,
737 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800738
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700739 XML_ERROR_FILE_NOT_FOUND,
Lee Thomason7f7b1622012-03-24 12:49:03 -0700740 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700741 XML_ERROR_ELEMENT_MISMATCH,
742 XML_ERROR_PARSING_ELEMENT,
743 XML_ERROR_PARSING_ATTRIBUTE,
744 XML_ERROR_IDENTIFYING_TAG,
745 XML_ERROR_PARSING_TEXT,
746 XML_ERROR_PARSING_CDATA,
747 XML_ERROR_PARSING_COMMENT,
748 XML_ERROR_PARSING_DECLARATION,
749 XML_ERROR_PARSING_UNKNOWN,
750 XML_ERROR_EMPTY_DOCUMENT,
751 XML_ERROR_MISMATCHED_ELEMENT,
752 XML_ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753};
754
755
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800756/** An attribute is a name-value pair. Elements have an arbitrary
757 number of attributes, each with a unique name.
758
759 @note The attributes are not XMLNodes. You may only query the
760 Next() attribute in a list.
761*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800762class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800763{
764 friend class XMLElement;
765public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800766 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
767 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
768 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800769
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800770 /** IntAttribute interprets the attribute as an integer, and returns the value.
771 If the value isn't an integer, 0 will be returned. There is no error checking;
772 use QueryIntAttribute() if you need error checking.
773 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800774 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800775 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800776 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800777 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800778 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800779 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800780 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800781 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800783
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800784 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
785 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700786 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800787 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800788 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800789 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800790 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800791 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800795 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800796 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800797
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800798 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800799 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800800 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800801 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800802 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800803 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800804 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800805 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800806 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800807 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800808 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800809 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800810
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800811private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800812 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800813
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800814 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800815 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800816 XMLAttribute( const XMLAttribute& ); // not supported
817 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800818 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800819
Lee Thomason6f381b72012-03-02 12:59:39 -0800820 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800821
Lee Thomason751da522012-02-10 08:50:51 -0800822 mutable StrPair name;
823 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800825 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826};
827
828
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800829/** The element is a container class. It has a value, the element name,
830 and can contain other elements, text, comments, and unknowns.
831 Elements also contain an arbitrary number of attributes.
832*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833class XMLElement : public XMLNode
834{
Lee Thomason2c85a712012-01-31 08:24:24 -0800835 friend class XMLBase;
836 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800837public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800838 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800839 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800840 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800841 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800842
Lee Thomason751da522012-02-10 08:50:51 -0800843 virtual XMLElement* ToElement() { return this; }
844 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800845 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800846
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800847 /** Given an attribute name, Attribute() returns the value
Lee Thomason92258152012-03-24 13:05:39 -0700848 for the attribute of that name, or null if none
849 exists. For example:
850
851 @verbatim
852 const char* value = ele->Attribute( "foo" );
853 @endverbatim
854
855 The 'value' parameter is normally null. However, if specified,
856 the attribute will only be returned if the 'name' and 'value'
857 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700858
859 @verbatim
860 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
861 @endverbatim
862
863 rather than:
864 @verbatim
865 if ( ele->Attribute( "foo" ) ) {
866 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
867 }
868 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800869 */
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700870 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800871
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800872 /** Given an attribute name, IntAttribute() returns the value
873 of the attribute interpreted as an integer. 0 will be
874 returned if there is an error. For a method with error
875 checking, see QueryIntAttribute()
876 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800877 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800878 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800879 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800880 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800881 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800882 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800883 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800884 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800885 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
886
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800887 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700888 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
889 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800890 doesn't exist. If successful, the result of the conversion
891 will be written to 'value'. If not successful, nothing will
892 be written to 'value'. This allows you to provide default
893 value:
894
895 @verbatim
896 int value = 10;
897 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
898 @endverbatim
899 */
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700900 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 -0800901 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700902 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 -0800903 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700904 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 -0800905 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700906 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 -0800907 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700908 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 -0800909
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800910 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700911 void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800912 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700913 void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800914 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700915 void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800916 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700917 void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800918 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700919 void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800920
U-Stream\Leeae25a442012-02-17 17:48:16 -0800921 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800922 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800923 */
924 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800925
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800926 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800927 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800928 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800929 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800930
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800931 /** Convenience function for easy access to the text inside an element. Although easy
932 and concise, GetText() is limited compared to getting the TiXmlText child
933 and accessing it directly.
934
935 If the first child of 'this' is a TiXmlText, the GetText()
936 returns the character string of the Text node, else null is returned.
937
938 This is a convenient method for getting the text of simple contained text:
939 @verbatim
940 <foo>This is text</foo>
941 const char* str = fooElement->GetText();
942 @endverbatim
943
944 'str' will be a pointer to "This is text".
945
946 Note that this function can be misleading. If the element foo was created from
947 this XML:
948 @verbatim
949 <foo><b>This is text</b></foo>
950 @endverbatim
951
952 then the value of str would be null. The first child node isn't a text node, it is
953 another element. From this XML:
954 @verbatim
955 <foo>This is <b>text</b></foo>
956 @endverbatim
957 GetText() will return "This is ".
958 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800959 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800960
Lee Thomason2c85a712012-01-31 08:24:24 -0800961 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800962 enum {
963 OPEN, // <foo>
964 CLOSED, // <foo/>
965 CLOSING // </foo>
966 };
967 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800968 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800969 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
970 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800971
Lee Thomason50adb4c2012-02-13 15:07:09 -0800972private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800973 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800974 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800975 XMLElement( const XMLElement& ); // not supported
976 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800977
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800978 XMLAttribute* FindAttribute( const char* name );
979 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800980 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800981 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800982
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800984 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800985};
986
987
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800988/** A document binds together all the functionality.
989 It can be saved, loaded, and printed to the screen.
990 All Nodes are connected and allocated to a Document.
991 If the Document is deleted, all its Nodes are also deleted.
992*/
Lee Thomason67d61312012-01-24 16:01:51 -0800993class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800994{
Lee Thomasond1983222012-02-06 08:41:24 -0800995 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800996public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800997 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -0800998 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -0800999 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001000
Lee Thomason751da522012-02-10 08:50:51 -08001001 virtual XMLDocument* ToDocument() { return this; }
1002 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -08001003
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001004 /**
1005 Parse an XML file from a character string.
1006 Returns XML_NO_ERROR (0) on success, or
1007 an errorID.
1008 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001009 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001010 /**
1011 Load an XML file from disk.
1012 Returns XML_NO_ERROR (0) on success, or
1013 an errorID.
1014 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001015 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001016 /**
1017 Load an XML file from disk. You are responsible
1018 for providing and closing the FILE*.
1019
1020 Returns XML_NO_ERROR (0) on success, or
1021 an errorID.
1022 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001023 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001024 /**
1025 Save the XML file to disk.
1026 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001027 void SaveFile( const char* filename );
1028
Lee Thomason6f381b72012-03-02 12:59:39 -08001029 bool ProcessEntities() const { return processEntities; }
1030
1031 /**
1032 Returns true if this document has a leading Byte Order Mark of UTF8.
1033 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001034 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001035
1036 /** Return the root element of DOM. Equivalent to FirstChildElement().
1037 To get the first node, use FirstChild().
1038 */
Lee Thomasond6277762012-02-22 16:00:12 -08001039 XMLElement* RootElement() { return FirstChildElement(); }
1040 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001041
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001042 /** Print the Document. If the Printer is not provided, it will
1043 print to stdout. If you provide Printer, this can print to a file:
1044 @verbatim
1045 XMLPrinter printer( fp );
1046 doc.Print( &printer );
1047 @endverbatim
1048
1049 Or you can use a printer to print to memory:
1050 @verbatim
1051 XMLPrinter printer;
1052 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001053 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001054 @endverbatim
1055 */
1056 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001057 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001058
Lee Thomason1ff38e02012-02-14 18:18:16 -08001059 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001060 Create a new Element associated with
1061 this Document. The memory for the Element
1062 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001063 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001064 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001065 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001066 Create a new Comment associated with
1067 this Document. The memory for the Comment
1068 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001069 */
1070 XMLComment* NewComment( const char* comment );
1071 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001072 Create a new Text associated with
1073 this Document. The memory for the Text
1074 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001075 */
1076 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001077 /**
1078 Create a new Declaration associated with
1079 this Document. The memory for the object
1080 is managed by the Document.
1081 */
1082 XMLDeclaration* NewDeclaration( const char* text );
1083 /**
1084 Create a new Unknown associated with
1085 this Document. The memory for the object
1086 is managed by the Document.
1087 */
1088 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001089
U-Stream\Leeae25a442012-02-17 17:48:16 -08001090 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001091 Delete a node associated with this documented.
1092 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001093 */
1094 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1095
Lee Thomason67d61312012-01-24 16:01:51 -08001096 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001097
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001098 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001099 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001100 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001101 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001102 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001103 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001104 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001105 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001106 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001107 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001108
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001109 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001110 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001111
Lee Thomason6f381b72012-03-02 12:59:39 -08001112 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1113 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001114
Lee Thomason3f57d272012-01-11 15:30:03 -08001115private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001116 XMLDocument( const XMLDocument& ); // not supported
1117 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001118 void InitDocument();
1119
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001120 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001121 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001122 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001123 const char* errorStr1;
1124 const char* errorStr2;
1125 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001126
1127 MemPoolT< sizeof(XMLElement) > elementPool;
1128 MemPoolT< sizeof(XMLAttribute) > attributePool;
1129 MemPoolT< sizeof(XMLText) > textPool;
1130 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001131};
1132
Lee Thomason7c913cd2012-01-26 18:32:34 -08001133
Lee Thomason3ffdd392012-03-28 17:27:55 -07001134/**
1135 A XMLHandle is a class that wraps a node pointer with null checks; this is
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001136 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
Lee Thomason3ffdd392012-03-28 17:27:55 -07001137 DOM structure. It is a separate utility class.
1138
1139 Take an example:
1140 @verbatim
1141 <Document>
1142 <Element attributeA = "valueA">
1143 <Child attributeB = "value1" />
1144 <Child attributeB = "value2" />
1145 </Element>
1146 <Document>
1147 @endverbatim
1148
1149 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
1150 easy to write a *lot* of code that looks like:
1151
1152 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001153 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001154 if ( root )
1155 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001156 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001157 if ( element )
1158 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001159 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001160 if ( child )
1161 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001162 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001163 if ( child2 )
1164 {
1165 // Finally do something useful.
1166 @endverbatim
1167
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001168 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
1169 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07001170 and correct to use:
1171
1172 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07001173 XMLHandle docHandle( &document );
1174 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07001175 if ( child2 )
1176 {
1177 // do something useful
1178 @endverbatim
1179
1180 Which is MUCH more concise and useful.
1181
1182 It is also safe to copy handles - internally they are nothing more than node pointers.
1183 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001184 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001185 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001186
1187 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001188*/
1189class XMLHandle
1190{
1191public:
1192 /// 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 -07001193 XMLHandle( XMLNode* _node ) { node = _node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001194 /// Create a handle from a node.
Lee Thomason8b899812012-04-04 15:58:16 -07001195 XMLHandle( XMLNode& _node ) { node = &_node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001196 /// Copy constructor
Lee Thomason8b899812012-04-04 15:58:16 -07001197 XMLHandle( const XMLHandle& ref ) { node = ref.node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001198 /// Assignment
Lee Thomason8b899812012-04-04 15:58:16 -07001199 XMLHandle operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001200
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001201 /// Get the first child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001202 XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001203 /// Get the first child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001204 XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001205 /// Get the last child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001206 XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001207 /// Get the last child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001208 XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001209 /// Get the previous sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001210 XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001211 /// Get the previous sibling element of this handle.
Lee Thomason5708f812012-03-28 17:46:41 -07001212 XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001213 /// Get the next sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001214 XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001215 /// Get the next sibling element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001216 XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001217
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001218 /// Safe cast to XMLNode. This can return null.
Lee Thomason8b899812012-04-04 15:58:16 -07001219 XMLNode* ToNode() { return node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001220 /// Safe cast to XMLElement. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001221 XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001222 /// Safe cast to XMLText. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001223 XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001224 /// Safe cast to XMLUnknown. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001225 XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001226 /// Safe cast to XMLDeclaration. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001227 XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001228
1229private:
1230 XMLNode* node;
1231};
1232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001233
1234/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001235 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1236 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07001237*/
1238class XMLConstHandle
1239{
1240public:
1241 XMLConstHandle( const XMLNode* _node ) { node = _node; }
1242 XMLConstHandle( const XMLNode& _node ) { node = &_node; }
1243 XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
1244
1245 XMLConstHandle operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
1246
1247 const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
1248 const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
1249 const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
1250 const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
1251 const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
1252 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
1253 const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
1254 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
1255
1256
1257 const XMLNode* ToNode() const { return node; }
1258 const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
1259 const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
1260 const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001261 const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
1262
Lee Thomason5cae8972012-01-24 18:03:07 -08001263private:
Lee Thomason8b899812012-04-04 15:58:16 -07001264 const XMLNode* node;
Lee Thomason56bdd022012-02-09 18:16:58 -08001265};
Lee Thomason6f381b72012-03-02 12:59:39 -08001266
Lee Thomason56bdd022012-02-09 18:16:58 -08001267
Lee Thomason857b8682012-01-25 17:50:25 -08001268/**
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001269 Printing functionality. The XMLPrinter gives you more
1270 options than the XMLDocument::Print() method.
Lee Thomason857b8682012-01-25 17:50:25 -08001271
1272 It can:
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001273 -# Print to memory.
Lee Thomason5cae8972012-01-24 18:03:07 -08001274 -# Print to a file you provide
Lee Thomason2c85a712012-01-31 08:24:24 -08001275 -# Print XML without a XMLDocument.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001276
Lee Thomason5cae8972012-01-24 18:03:07 -08001277 Print to Memory
1278
1279 @verbatim
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001280 XMLPrinter printer;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001281 doc->Print( &printer );
U-Lama\Lee560bd472011-12-28 19:42:49 -08001282 SomeFunctior( printer.CStr() );
1283 @endverbatim
U-Stream\Leeae25a442012-02-17 17:48:16 -08001284
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001285 Print to a File
1286
1287 You provide the file pointer.
1288 @verbatim
1289 XMLPrinter printer( fp );
1290 doc.Print( &printer );
1291 @endverbatim
1292
1293 Print without a XMLDocument
1294
1295 When loading, an XML parser is very useful. However, sometimes
1296 when saving, it just gets in the way. The code is often set up
1297 for streaming, and constructing the DOM is just overhead.
1298
1299 The Printer supports the streaming case. The following code
1300 prints out a trivially simple XML file without ever creating
1301 an XML document.
1302
1303 @verbatim
1304 XMLPrinter printer( fp );
1305 printer.OpenElement( "foo" );
1306 printer.PushAttribute( "foo", "bar" );
1307 printer.CloseElement();
1308 @endverbatim
1309*/
1310class XMLPrinter : public XMLVisitor
1311{
1312public:
1313 /** Construct the printer. If the FILE* is specified,
1314 this will print to the FILE. Else it will print
1315 to memory, and the result is available in CStr()
1316 */
1317 XMLPrinter( FILE* file=0 );
1318 ~XMLPrinter() {}
1319
1320 /** If streaming, write the BOM and declaration. */
1321 void PushHeader( bool writeBOM, bool writeDeclaration );
1322 /** If streaming, start writing an element.
1323 The element must be closed with CloseElement()
1324 */
1325 void OpenElement( const char* name );
1326 /// If streaming, add an attribute to an open element.
1327 void PushAttribute( const char* name, const char* value );
1328 void PushAttribute( const char* name, int value );
1329 void PushAttribute( const char* name, unsigned value );
1330 void PushAttribute( const char* name, bool value );
1331 void PushAttribute( const char* name, double value );
1332 /// If streaming, close the Element.
1333 void CloseElement();
1334
1335 /// Add a text node.
1336 void PushText( const char* text, bool cdata=false );
1337 /// Add a comment
1338 void PushComment( const char* comment );
1339
1340 void PushDeclaration( const char* value );
1341 void PushUnknown( const char* value );
1342
1343 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
1344 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1345
1346 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1347 virtual bool VisitExit( const XMLElement& element );
1348
1349 virtual bool Visit( const XMLText& text );
1350 virtual bool Visit( const XMLComment& comment );
1351 virtual bool Visit( const XMLDeclaration& declaration );
1352 virtual bool Visit( const XMLUnknown& unknown );
1353
1354 /**
1355 If in print to memory mode, return a pointer to
1356 the XML file in memory.
1357 */
1358 const char* CStr() const { return buffer.Mem(); }
1359
1360private:
1361 void SealElement();
1362 void PrintSpace( int depth );
1363 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
1364 void Print( const char* format, ... );
1365
1366 bool elementJustOpened;
1367 bool firstElement;
1368 FILE* fp;
1369 int depth;
1370 int textDepth;
1371 bool processEntities;
1372
1373 enum {
1374 ENTITY_RANGE = 64,
1375 BUF_SIZE = 200
1376 };
1377 bool entityFlag[ENTITY_RANGE];
1378 bool restrictedEntityFlag[ENTITY_RANGE];
1379
1380 DynArray< const char*, 10 > stack;
1381 DynArray< char, 20 > buffer, accumulator;
1382};
1383
1384
1385} // tinyxml2
1386
1387
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -07001388// What follows is the docs for the examples.
1389// I'd like the docs to be just before the
1390// actual examples in xmltest.cpp, but I
1391// can't seem to get doxygen to do that. It
1392// would be a wonderful patch if anyone figures
1393// it out.
1394
1395/** @page Example-1 Load an XML File
1396 * @dontinclude ./xmltest.cpp
1397 * Basic XML file loading.
1398 * The basic syntax to load an XML file from
1399 * disk and check for an error. (ErrorID()
1400 * will return 0 for no error.)
1401 * @skip example_1()
1402 * @until }
1403 */
1404
1405
1406/** @page Example-2 Parse an XML from char buffer
1407 * @dontinclude ./xmltest.cpp
1408 * Basic XML string parsing.
1409 * The basic syntax to parse an XML for
1410 * a char* and check for an error. (ErrorID()
1411 * will return 0 for no error.)
1412 * @skip example_2()
1413 * @until }
1414 */
1415
1416/** @page Example-3 Get information out of XML
1417 @dontinclude ./xmltest.cpp
1418 In this example, we navigate a simple XML
1419 file, and read some interesting text. Note
1420 that this is examlpe doesn't use error
1421 checking; working code should check for null
1422 pointers when walking an XML tree, or use
1423 XMLHandle.
1424
1425 (The XML is an excerpt from "dream.xml").
1426
1427 @skip example_3
1428 @until </PLAY>";
1429
1430 The structure of the XML file is:
1431
1432 <ul>
1433 <li>(declaration)</li>
1434 <li>(dtd stuff)</li>
1435 <li>Element "PLAY"</li>
1436 <ul>
1437 <li>Element "TITLE"</li>
1438 <ul>
1439 <li>Text "A Midsummer Night's Dream"</li>
1440 </ul>
1441 </ul>
1442 </ul>
1443
1444 For this example, we want to print out the
1445 title of the play. The text of the title (what
1446 we want) is child of the "TITLE" element which
1447 is a child of the "PLAY" element.
1448
1449 We want to skip the declaration and dtd, so the
1450 method FirstChildElement() is a good choice. The
1451 FirstChildElement() of the Document is the "PLAY"
1452 Element, the FirstChildElement() of the "PLAY" Element
1453 is the "TITLE" Element.
1454
1455 @until ( "TITLE" );
1456
1457 We can then use the convenience function GetText()
1458 to get the title of the play.
1459
1460 @until title );
1461
1462 Text is just another Node in the XML DOM. And in
1463 fact you should be a little cautious with it, as
1464 text nodes can contain elements.
1465
1466 @verbatim
1467 Consider: A Midsummer Night's <b>Dream</b>
1468 @endverbatim
1469
1470 It is more correct to actually query the Text Node
1471 if in doubt:
1472
1473 @until title );
1474
1475 Noting that here we use FirstChild() since we are
1476 looking for XMLText, not an element, and ToText()
1477 is a cast from a Node to a XMLText.
1478*/
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001479
1480#endif // TINYXML2_INCLUDED