blob: dceb842e68ae4f49f183eae2719e061b9397ce03 [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 Thomason2c85a712012-01-31 08:24:24 -080027
U-Lama\Lee4cee6112011-12-31 14:58:18 -080028#include <limits.h>
Lee Thomasonce0763e2012-01-11 15:43:54 -080029#include <ctype.h>
30#include <stdio.h>
Lee Thomason52913d12012-03-13 19:51:59 -070031#include <memory.h> // Needed by mac.
U-Lama\Lee4cee6112011-12-31 14:58:18 -080032
Lee Thomason7d00b9a2012-02-27 17:54:22 -080033/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080034 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080035 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080036*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080037/*
38 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -080039
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080040*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080041
U-Lama\Lee4cee6112011-12-31 14:58:18 -080042#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
43 #ifndef DEBUG
44 #define DEBUG
45 #endif
46#endif
47
48
49#if defined(DEBUG)
50 #if defined(_MSC_VER)
51 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
52 #elif defined (ANDROID_NDK)
53 #include <android/log.h>
54 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
55 #else
56 #include <assert.h>
57 #define TIXMLASSERT assert
58 #endif
59#else
60 #define TIXMLASSERT( x ) {}
61#endif
62
U-Lama\Leee13c3e62011-12-28 14:36:55 -080063
Lee Thomason1a1d4a72012-02-15 09:09:25 -080064// Deprecated library function hell. Compilers want to use the
65// new safe versions. This probably doesn't fully address the problem,
66// but it gets closer. There are too many compilers for me to fully
67// test. If you get compilation troubles, undefine TIXML_SAFE
68
69#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
70 // Microsoft visual studio, version 2005 and higher.
71 #define TIXML_SNPRINTF _snprintf_s
72 #define TIXML_SSCANF sscanf_s
73#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
74 // Microsoft visual studio, version 6 and higher.
75 //#pragma message( "Using _sn* functions." )
76 #define TIXML_SNPRINTF _snprintf
77 #define TIXML_SSCANF sscanf
78#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080079 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080080 //#warning( "Using sn* functions." )
81 #define TIXML_SNPRINTF snprintf
82 #define TIXML_SSCANF sscanf
83#else
84 #define TIXML_SNPRINTF snprintf
85 #define TIXML_SSCANF sscanf
86#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
Lee Thomason27057312012-03-02 09:04:53 -080088static const int TIXML2_MAJOR_VERSION = 0;
89static const int TIXML2_MINOR_VERSION = 9;
90static const int TIXML2_PATCH_VERSION = 0;
Lee Thomason1ff38e02012-02-14 18:18:16 -080091
U-Lama\Leee13c3e62011-12-28 14:36:55 -080092namespace tinyxml2
93{
Lee Thomasonce0763e2012-01-11 15:43:54 -080094class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080095class XMLElement;
96class XMLAttribute;
97class XMLComment;
98class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -080099class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800100class XMLDeclaration;
101class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800102
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800103class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800104
U-Stream\Leeae25a442012-02-17 17:48:16 -0800105/*
106 A class that wraps strings. Normally stores the start and end
107 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800108 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800109 manage) a traditional char[]
110*/
Lee Thomason39ede242012-01-20 11:27:56 -0800111class StrPair
112{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800113public:
Lee Thomason39ede242012-01-20 11:27:56 -0800114 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800115 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800116 NEEDS_NEWLINE_NORMALIZATION = 0x02,
117
118 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800119 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800120 ATTRIBUTE_NAME = 0,
121 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800122 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700123 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800124 };
125
126 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800127 ~StrPair();
128
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700129 void Set( char* start_, char* end_, int flags_ ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800130 Reset();
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700131 this->start = start_; this->end = end_; this->flags = flags_ | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800132 }
133 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800134 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800135
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
137 void SetStr( const char* str, int flags=0 );
138
Lee Thomason56bdd022012-02-09 18:16:58 -0800139 char* ParseText( char* in, const char* endTag, int strFlags );
140 char* ParseName( char* in );
141
Lee Thomason2c85a712012-01-31 08:24:24 -0800142
Lee Thomason39ede242012-01-20 11:27:56 -0800143private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800144 void Reset();
145
Lee Thomasone4422302012-01-20 17:59:50 -0800146 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800147 NEEDS_FLUSH = 0x100,
148 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800149 };
150
Lee Thomason39ede242012-01-20 11:27:56 -0800151 // After parsing, if *end != 0, it can be set to zero.
152 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800153 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800154 char* end;
155};
156
U-Lama\Lee560bd472011-12-28 19:42:49 -0800157
U-Stream\Leeae25a442012-02-17 17:48:16 -0800158/*
159 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
160 Has a small initial memory pool, so that low or no usage will not
161 cause a call to new/delete
162*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800163template <class T, int INIT>
164class DynArray
165{
166public:
167 DynArray< T, INIT >()
168 {
169 mem = pool;
170 allocated = INIT;
171 size = 0;
172 }
173 ~DynArray()
174 {
175 if ( mem != pool ) {
176 delete mem;
177 }
178 }
179 void Push( T t )
180 {
181 EnsureCapacity( size+1 );
182 mem[size++] = t;
183 }
184
185 T* PushArr( int count )
186 {
187 EnsureCapacity( size+count );
188 T* ret = &mem[size];
189 size += count;
190 return ret;
191 }
192 T Pop() {
193 return mem[--size];
194 }
195 void PopArr( int count )
196 {
197 TIXMLASSERT( size >= count );
198 size -= count;
199 }
200
U-Stream\Leeae25a442012-02-17 17:48:16 -0800201 bool Empty() const { return size == 0; }
202 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
203 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
204 int Size() const { return size; }
205 int Capacity() const { return allocated; }
206 const T* Mem() const { return mem; }
207 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800208
209
210private:
211 void EnsureCapacity( int cap ) {
212 if ( cap > allocated ) {
213 int newAllocated = cap * 2;
214 T* newMem = new T[newAllocated];
215 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
216 if ( mem != pool ) delete [] mem;
217 mem = newMem;
218 allocated = newAllocated;
219 }
220 }
221
222 T* mem;
223 T pool[INIT];
224 int allocated; // objects allocated
225 int size; // number objects in use
226};
227
Lee Thomason50adb4c2012-02-13 15:07:09 -0800228
U-Stream\Leeae25a442012-02-17 17:48:16 -0800229/*
230 Parent virtual class a a pool for fast allocation
231 and deallocation of objects.
232*/
Lee Thomasond1983222012-02-06 08:41:24 -0800233class MemPool
234{
235public:
236 MemPool() {}
237 virtual ~MemPool() {}
238
239 virtual int ItemSize() const = 0;
240 virtual void* Alloc() = 0;
241 virtual void Free( void* ) = 0;
242};
243
Lee Thomason50adb4c2012-02-13 15:07:09 -0800244
U-Stream\Leeae25a442012-02-17 17:48:16 -0800245/*
246 Template child class to create pools of the correct type.
247*/
Lee Thomasond1983222012-02-06 08:41:24 -0800248template< int SIZE >
249class MemPoolT : public MemPool
250{
251public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800252 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800253 ~MemPoolT() {
254 // Delete the blocks.
255 for( int i=0; i<blockPtrs.Size(); ++i ) {
256 delete blockPtrs[i];
257 }
258 }
259
260 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800261 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800262
263 virtual void* Alloc() {
264 if ( !root ) {
265 // Need a new block.
266 Block* block = new Block();
267 blockPtrs.Push( block );
268
269 for( int i=0; i<COUNT-1; ++i ) {
270 block->chunk[i].next = &block->chunk[i+1];
271 }
272 block->chunk[COUNT-1].next = 0;
273 root = block->chunk;
274 }
275 void* result = root;
276 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800277
278 ++currentAllocs;
279 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
280 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800281 return result;
282 }
283 virtual void Free( void* mem ) {
284 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800285 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800286 Chunk* chunk = (Chunk*)mem;
287 memset( chunk, 0xfe, sizeof(Chunk) );
288 chunk->next = root;
289 root = chunk;
290 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800291 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800292 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
293 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800294 }
Lee Thomasond1983222012-02-06 08:41:24 -0800295
296private:
297 enum { COUNT = 1024/SIZE };
298 union Chunk {
299 Chunk* next;
300 char mem[SIZE];
301 };
302 struct Block {
303 Chunk chunk[COUNT];
304 };
305 DynArray< Block*, 10 > blockPtrs;
306 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800307
308 int currentAllocs;
309 int nAllocs;
310 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800311};
312
Lee Thomason2c85a712012-01-31 08:24:24 -0800313
Lee Thomason56bdd022012-02-09 18:16:58 -0800314
315/**
316 Implements the interface to the "Visitor pattern" (see the Accept() method.)
317 If you call the Accept() method, it requires being passed a XMLVisitor
318 class to handle callbacks. For nodes that contain other nodes (Document, Element)
319 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
320 are simply called with Visit().
321
322 If you return 'true' from a Visit method, recursive parsing will continue. If you return
323 false, <b>no children of this node or its sibilings</b> will be Visited.
324
325 All flavors of Visit methods have a default implementation that returns 'true' (continue
326 visiting). You need to only override methods that are interesting to you.
327
328 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
329
330 You should never change the document from a callback.
331
332 @sa XMLNode::Accept()
333*/
334class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800335{
336public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800337 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800338
Lee Thomason56bdd022012-02-09 18:16:58 -0800339 /// Visit a document.
340 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
341 /// Visit a document.
342 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
343
344 /// Visit an element.
345 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
346 /// Visit an element.
347 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
348
349 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800350 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800351 /// Visit a text node
352 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
353 /// Visit a comment node
354 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
355 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800356 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800357};
358
359
U-Stream\Leeae25a442012-02-17 17:48:16 -0800360/*
361 Utility functionality.
362*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800363class XMLUtil
364{
Lee Thomasond1983222012-02-06 08:41:24 -0800365public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800366 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
367 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800368 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
369 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800370
371 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
372 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800373 if ( p == q ) {
374 return true;
375 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800376 while( *p && *q && *p == *q && n<nChar ) {
377 ++p; ++q; ++n;
378 }
379 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
380 return true;
381 }
382 return false;
383 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700384 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800385 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
386 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800387
388 static const char* ReadBOM( const char* p, bool* hasBOM );
389 // p is the starting location,
390 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800391 static const char* GetCharacterRef( const char* p, char* value, int* length );
392 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800393};
394
Lee Thomason5cae8972012-01-24 18:03:07 -0800395
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800396/** XMLNode is a base class for every object that is in the
397 XML Document Object Model (DOM), except XMLAttributes.
398 Nodes have siblings, a parent, and children which can
399 be navigated. A node is always in a XMLDocument.
400 The type of a TiXmlNode can be queried, and it can
401 be cast to its more defined type.
402
403 An XMLDocument allocates memory for all its Nodes.
404 When the XMLDocument gets deleted, all its Nodes
405 will also be deleted.
406
407 @verbatim
408 A Document can contain: Element (container or leaf)
409 Comment (leaf)
410 Unknown (leaf)
411 Declaration( leaf )
412
413 An Element can contain: Element (container or leaf)
414 Text (leaf)
415 Attributes (not on tree)
416 Comment (leaf)
417 Unknown (leaf)
418
419 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800420*/
Lee Thomasond1983222012-02-06 08:41:24 -0800421class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800422{
423 friend class XMLDocument;
424 friend class XMLElement;
425public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800426
427 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800428 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800429 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800430 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800431
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800432 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
433 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
434 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
435 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
436 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
437 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800438
Lee Thomason50f97b22012-02-11 16:33:40 -0800439 virtual const XMLElement* ToElement() const { return 0; }
440 virtual const XMLText* ToText() const { return 0; }
441 virtual const XMLComment* ToComment() const { return 0; }
442 virtual const XMLDocument* ToDocument() const { return 0; }
443 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
444 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800445
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800446 /** The meaning of 'value' changes for the specific type.
447 @verbatim
448 Document: empy
449 Element: name of the element
450 Comment: the comment text
451 Unknown: the tag contents
452 Text: the text string
453 @endverbatim
454 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800455 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800456 /** Set the Value of an XML node.
457 @sa Value()
458 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800459 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800460
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800461 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800462 const XMLNode* Parent() const { return parent; }
463 XMLNode* Parent() { return parent; }
464
Lee Thomason50f97b22012-02-11 16:33:40 -0800465 /// Returns true if this node has no children.
466 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800467
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800468 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800469 const XMLNode* FirstChild() const { return firstChild; }
470 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800471 /** Get the first child element, or optionally the first child
472 element with the specified name.
473 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800474 const XMLElement* FirstChildElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700475 XMLElement* FirstChildElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value_ )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800476
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800477 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800478 const XMLNode* LastChild() const { return lastChild; }
479 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800480
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800481 /** Get the last child element or optionally the last child
482 element with the specified name.
483 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800484 const XMLElement* LastChildElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700485 XMLElement* LastChildElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value_) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800486
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800487 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800488 const XMLNode* PreviousSibling() const { return prev; }
489 XMLNode* PreviousSibling() { return prev; }
490
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800491 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800492 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700493 XMLElement* PreviousSiblingElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value_ ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800494
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800495 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800496 const XMLNode* NextSibling() const { return next; }
497 XMLNode* NextSibling() { return next; }
498
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800499 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800500 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700501 XMLElement* NextSiblingElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value_ ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800502
Lee Thomason1ff38e02012-02-14 18:18:16 -0800503 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800504 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800505 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800506 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800507
508 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800509 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800510 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800511 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800512 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800513 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800514 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800515 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800516 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
517
U-Stream\Leeae25a442012-02-17 17:48:16 -0800518 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800519 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800520 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800521 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800522
523 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800524 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800525 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800526 void DeleteChild( XMLNode* node );
527
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800528 /**
529 Make a copy of this node, but not its children.
530 You may pass in a Document pointer that will be
531 the owner of the new Node. If the 'document' is
532 null, then the node returned will be allocated
533 from the current Document. (this->GetDocument())
534
535 Note: if called on a XMLDocument, this will return null.
536 */
537 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
538
539 /**
540 Test if 2 nodes are the same, but don't test children.
541 The 2 nodes do not need to be in the same Document.
542
543 Note: if called on a XMLDocument, this will return false.
544 */
545 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
546
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800547 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
548 XML tree will be conditionally visited and the host will be called back
549 via the TiXmlVisitor interface.
550
551 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
552 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
553 interface versus any other.)
554
555 The interface has been based on ideas from:
556
557 - http://www.saxproject.org/
558 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
559
560 Which are both good references for "visiting".
561
562 An example of using Accept():
563 @verbatim
564 TiXmlPrinter printer;
565 tinyxmlDoc.Accept( &printer );
566 const char* xmlcstr = printer.CStr();
567 @endverbatim
568 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800569 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800570
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800571 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800572 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800573
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574protected:
575 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800576 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800577 XMLNode( const XMLNode& ); // not supported
578 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800579
Lee Thomason3f57d272012-01-11 15:30:03 -0800580 XMLDocument* document;
581 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800582 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800583
584 XMLNode* firstChild;
585 XMLNode* lastChild;
586
587 XMLNode* prev;
588 XMLNode* next;
589
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800590private:
Lee Thomasond1983222012-02-06 08:41:24 -0800591 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800592 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800593};
594
595
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800596/** XML text.
597
598 Note that a text node can have child element nodes, for example:
599 @verbatim
600 <root>This is <b>bold</b></root>
601 @endverbatim
602
603 A text node can have 2 ways to output the next. "normal" output
604 and CDATA. It will default to the mode it was parsed from the XML file and
605 you generally want to leave it alone, but you can change the output mode with
606 SetCDATA() and query it with CDATA().
607*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800608class XMLText : public XMLNode
609{
Lee Thomason2c85a712012-01-31 08:24:24 -0800610 friend class XMLBase;
611 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800612public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800613 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800614
Lee Thomason751da522012-02-10 08:50:51 -0800615 virtual XMLText* ToText() { return this; }
616 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800617
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800618 /// Declare whether this should be CDATA or standard text.
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700619 void SetCData( bool isCData_ ) { this->isCData = isCData_; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800620 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800621 bool CData() const { return isCData; }
622
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800623 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800624 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
625 virtual bool ShallowEqual( const XMLNode* compare ) const;
626
Lee Thomason5492a1c2012-01-23 15:32:10 -0800627
628protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800629 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
630 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800631 XMLText( const XMLText& ); // not supported
632 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800633
634private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800635 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800636};
637
638
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800639/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800640class XMLComment : public XMLNode
641{
Lee Thomason2c85a712012-01-31 08:24:24 -0800642 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800643public:
Lee Thomason751da522012-02-10 08:50:51 -0800644 virtual XMLComment* ToComment() { return this; }
645 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800646
Lee Thomason56bdd022012-02-09 18:16:58 -0800647 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800648
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800649 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800650 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
651 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800652
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800654 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800655 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800656 XMLComment( const XMLComment& ); // not supported
657 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658
Lee Thomason3f57d272012-01-11 15:30:03 -0800659private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800660};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800661
662
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800663/** In correct XML the declaration is the first entry in the file.
664 @verbatim
665 <?xml version="1.0" standalone="yes"?>
666 @endverbatim
667
668 TinyXML2 will happily read or write files without a declaration,
669 however.
670
671 The text of the declaration isn't interpreted. It is parsed
672 and written as a string.
673*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800674class XMLDeclaration : public XMLNode
675{
676 friend class XMLDocument;
677public:
678 virtual XMLDeclaration* ToDeclaration() { return this; }
679 virtual const XMLDeclaration* ToDeclaration() const { return this; }
680
681 virtual bool Accept( XMLVisitor* visitor ) const;
682
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800683 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800684 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
685 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800686
687protected:
688 XMLDeclaration( XMLDocument* doc );
689 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800690 XMLDeclaration( const XMLDeclaration& ); // not supported
691 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800692};
693
694
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800695/** Any tag that tinyXml doesn't recognize is saved as an
696 unknown. It is a tag of text, but should not be modified.
697 It will be written back to the XML, unchanged, when the file
698 is saved.
699
700 DTD tags get thrown into TiXmlUnknowns.
701*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800702class XMLUnknown : public XMLNode
703{
704 friend class XMLDocument;
705public:
706 virtual XMLUnknown* ToUnknown() { return this; }
707 virtual const XMLUnknown* ToUnknown() const { return this; }
708
709 virtual bool Accept( XMLVisitor* visitor ) const;
710
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800711 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800712 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
713 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800714
715protected:
716 XMLUnknown( XMLDocument* doc );
717 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800718 XMLUnknown( const XMLUnknown& ); // not supported
719 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800720};
721
722
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800724 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800725 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800726
Lee Thomason1ff38e02012-02-14 18:18:16 -0800727 NO_ATTRIBUTE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800728 WRONG_ATTRIBUTE_TYPE,
729
730 ERROR_FILE_NOT_FOUND,
731 ERROR_ELEMENT_MISMATCH,
732 ERROR_PARSING_ELEMENT,
733 ERROR_PARSING_ATTRIBUTE,
734 ERROR_IDENTIFYING_TAG,
735 ERROR_PARSING_TEXT,
736 ERROR_PARSING_CDATA,
737 ERROR_PARSING_COMMENT,
738 ERROR_PARSING_DECLARATION,
Lee Thomasond6277762012-02-22 16:00:12 -0800739 ERROR_PARSING_UNKNOWN,
740 ERROR_EMPTY_DOCUMENT,
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800741 ERROR_MISMATCHED_ELEMENT,
742 ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800743};
744
745
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800746/** An attribute is a name-value pair. Elements have an arbitrary
747 number of attributes, each with a unique name.
748
749 @note The attributes are not XMLNodes. You may only query the
750 Next() attribute in a list.
751*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800752class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800753{
754 friend class XMLElement;
755public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800756 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
757 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
758 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800759
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800760 /** IntAttribute interprets the attribute as an integer, and returns the value.
761 If the value isn't an integer, 0 will be returned. There is no error checking;
762 use QueryIntAttribute() if you need error checking.
763 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800764 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800765 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800766 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800767 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800769 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800770 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800771 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800773
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800774 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
775 in the provided paremeter. The function will return XML_NO_ERROR on success,
776 and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
777 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800778 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800779 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800780 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800781 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800783 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800784 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800785 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800786 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800789 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800790 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800791 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800793 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800794 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800795 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800796 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800797 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800798 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800799 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800800
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800802 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800803
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800804 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800805 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800806 XMLAttribute( const XMLAttribute& ); // not supported
807 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800808 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800809
Lee Thomason6f381b72012-03-02 12:59:39 -0800810 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800811
Lee Thomason751da522012-02-10 08:50:51 -0800812 mutable StrPair name;
813 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800814 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800815 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800816};
817
818
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800819/** The element is a container class. It has a value, the element name,
820 and can contain other elements, text, comments, and unknowns.
821 Elements also contain an arbitrary number of attributes.
822*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823class XMLElement : public XMLNode
824{
Lee Thomason2c85a712012-01-31 08:24:24 -0800825 friend class XMLBase;
826 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800827public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800828 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800829 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800830 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800831 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800832
Lee Thomason751da522012-02-10 08:50:51 -0800833 virtual XMLElement* ToElement() { return this; }
834 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800835 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800836
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800837 /** Given an attribute name, Attribute() returns the value
838 for the attribute of that name, or null if none exists.
839 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800840 const char* Attribute( const char* name ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return 0; return a->Value(); }
Lee Thomason751da522012-02-10 08:50:51 -0800841
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800842 /** Given an attribute name, IntAttribute() returns the value
843 of the attribute interpreted as an integer. 0 will be
844 returned if there is an error. For a method with error
845 checking, see QueryIntAttribute()
846 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800847 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800848 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800849 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800850 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800851 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800852 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800853 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800854 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800855 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
856
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800857 /** Given an attribute name, QueryIntAttribute() returns
858 XML_NO_ERROR, WRONG_ATTRIBUTE_TYPE if the conversion
859 can't be performed, or NO_ATTRIBUTE if the attribute
860 doesn't exist. If successful, the result of the conversion
861 will be written to 'value'. If not successful, nothing will
862 be written to 'value'. This allows you to provide default
863 value:
864
865 @verbatim
866 int value = 10;
867 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
868 @endverbatim
869 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800870 int QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntValue( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800871 /// See QueryIntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800872 int QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedValue( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800873 /// See QueryIntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800874 int QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolValue( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800875 /// See QueryIntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800876 int QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleValue( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800877 /// See QueryIntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800878 int QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatValue( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800879
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800880 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800881 void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800882 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800883 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800884 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800885 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800886 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800887 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800888 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800889 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800890
U-Stream\Leeae25a442012-02-17 17:48:16 -0800891 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800893 */
894 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800895
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800896 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800897 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800898 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800899 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800900
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800901 /** Convenience function for easy access to the text inside an element. Although easy
902 and concise, GetText() is limited compared to getting the TiXmlText child
903 and accessing it directly.
904
905 If the first child of 'this' is a TiXmlText, the GetText()
906 returns the character string of the Text node, else null is returned.
907
908 This is a convenient method for getting the text of simple contained text:
909 @verbatim
910 <foo>This is text</foo>
911 const char* str = fooElement->GetText();
912 @endverbatim
913
914 'str' will be a pointer to "This is text".
915
916 Note that this function can be misleading. If the element foo was created from
917 this XML:
918 @verbatim
919 <foo><b>This is text</b></foo>
920 @endverbatim
921
922 then the value of str would be null. The first child node isn't a text node, it is
923 another element. From this XML:
924 @verbatim
925 <foo>This is <b>text</b></foo>
926 @endverbatim
927 GetText() will return "This is ".
928 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800929 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800930
Lee Thomason2c85a712012-01-31 08:24:24 -0800931 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800932 enum {
933 OPEN, // <foo>
934 CLOSED, // <foo/>
935 CLOSING // </foo>
936 };
937 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800938 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800939 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
940 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800941
Lee Thomason50adb4c2012-02-13 15:07:09 -0800942private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800943 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800944 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800945 XMLElement( const XMLElement& ); // not supported
946 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800947
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800948 XMLAttribute* FindAttribute( const char* name );
949 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800950 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800951 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800952
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800954 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800955};
956
957
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800958/** A document binds together all the functionality.
959 It can be saved, loaded, and printed to the screen.
960 All Nodes are connected and allocated to a Document.
961 If the Document is deleted, all its Nodes are also deleted.
962*/
Lee Thomason67d61312012-01-24 16:01:51 -0800963class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800964{
Lee Thomasond1983222012-02-06 08:41:24 -0800965 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800966public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800967 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -0800968 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -0800969 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800970
Lee Thomason751da522012-02-10 08:50:51 -0800971 virtual XMLDocument* ToDocument() { return this; }
972 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800973
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800974 /**
975 Parse an XML file from a character string.
976 Returns XML_NO_ERROR (0) on success, or
977 an errorID.
978 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800979 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800980 /**
981 Load an XML file from disk.
982 Returns XML_NO_ERROR (0) on success, or
983 an errorID.
984 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800985 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800986 /**
987 Load an XML file from disk. You are responsible
988 for providing and closing the FILE*.
989
990 Returns XML_NO_ERROR (0) on success, or
991 an errorID.
992 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800993 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800994 /**
995 Save the XML file to disk.
996 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800997 void SaveFile( const char* filename );
998
Lee Thomason6f381b72012-03-02 12:59:39 -0800999 bool ProcessEntities() const { return processEntities; }
1000
1001 /**
1002 Returns true if this document has a leading Byte Order Mark of UTF8.
1003 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001004 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001005
1006 /** Return the root element of DOM. Equivalent to FirstChildElement().
1007 To get the first node, use FirstChild().
1008 */
Lee Thomasond6277762012-02-22 16:00:12 -08001009 XMLElement* RootElement() { return FirstChildElement(); }
1010 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001012 /** Print the Document. If the Printer is not provided, it will
1013 print to stdout. If you provide Printer, this can print to a file:
1014 @verbatim
1015 XMLPrinter printer( fp );
1016 doc.Print( &printer );
1017 @endverbatim
1018
1019 Or you can use a printer to print to memory:
1020 @verbatim
1021 XMLPrinter printer;
1022 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001023 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001024 @endverbatim
1025 */
1026 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001027 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001028
Lee Thomason1ff38e02012-02-14 18:18:16 -08001029 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001030 Create a new Element associated with
1031 this Document. The memory for the Element
1032 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001033 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001034 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001035 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001036 Create a new Comment associated with
1037 this Document. The memory for the Comment
1038 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001039 */
1040 XMLComment* NewComment( const char* comment );
1041 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001042 Create a new Text associated with
1043 this Document. The memory for the Text
1044 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001045 */
1046 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001047 /**
1048 Create a new Declaration associated with
1049 this Document. The memory for the object
1050 is managed by the Document.
1051 */
1052 XMLDeclaration* NewDeclaration( const char* text );
1053 /**
1054 Create a new Unknown associated with
1055 this Document. The memory for the object
1056 is managed by the Document.
1057 */
1058 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001059
U-Stream\Leeae25a442012-02-17 17:48:16 -08001060 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001061 Delete a node associated with this documented.
1062 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001063 */
1064 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1065
Lee Thomason67d61312012-01-24 16:01:51 -08001066 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001067
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001068 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001069 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001070 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001071 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001072 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001073 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001074 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001075 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001076 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001077 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001079 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001080 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001081
Lee Thomason6f381b72012-03-02 12:59:39 -08001082 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1083 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001084
Lee Thomason3f57d272012-01-11 15:30:03 -08001085private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001086 XMLDocument( const XMLDocument& ); // not supported
1087 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001088 void InitDocument();
1089
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001090 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001091 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001092 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001093 const char* errorStr1;
1094 const char* errorStr2;
1095 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001096
1097 MemPoolT< sizeof(XMLElement) > elementPool;
1098 MemPoolT< sizeof(XMLAttribute) > attributePool;
1099 MemPoolT< sizeof(XMLText) > textPool;
1100 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001101};
1102
Lee Thomason7c913cd2012-01-26 18:32:34 -08001103
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001104
1105/**
1106 Printing functionality. The XMLPrinter gives you more
1107 options than the XMLDocument::Print() method.
1108
1109 It can:
1110 -# Print to memory.
1111 -# Print to a file you provide
1112 -# Print XML without a XMLDocument.
1113
1114 Print to Memory
1115
1116 @verbatim
1117 XMLPrinter printer;
1118 doc->Print( &printer );
1119 SomeFunctior( printer.CStr() );
1120 @endverbatim
1121
1122 Print to a File
1123
1124 You provide the file pointer.
1125 @verbatim
1126 XMLPrinter printer( fp );
1127 doc.Print( &printer );
1128 @endverbatim
1129
1130 Print without a XMLDocument
1131
1132 When loading, an XML parser is very useful. However, sometimes
1133 when saving, it just gets in the way. The code is often set up
1134 for streaming, and constructing the DOM is just overhead.
1135
1136 The Printer supports the streaming case. The following code
1137 prints out a trivially simple XML file without ever creating
1138 an XML document.
1139
1140 @verbatim
1141 XMLPrinter printer( fp );
1142 printer.OpenElement( "foo" );
1143 printer.PushAttribute( "foo", "bar" );
1144 printer.CloseElement();
1145 @endverbatim
1146*/
1147class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001148{
1149public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001150 /** Construct the printer. If the FILE* is specified,
1151 this will print to the FILE. Else it will print
1152 to memory, and the result is available in CStr()
1153 */
1154 XMLPrinter( FILE* file=0 );
1155 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001156
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001157 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001158 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001159 /** If streaming, start writing an element.
1160 The element must be closed with CloseElement()
1161 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001162 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001163 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001164 void PushAttribute( const char* name, const char* value );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001165 void PushAttribute( const char* name, int value );
1166 void PushAttribute( const char* name, unsigned value );
1167 void PushAttribute( const char* name, bool value );
1168 void PushAttribute( const char* name, double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001169 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001170 void CloseElement();
1171
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001172 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001173 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001174 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001175 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001176
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001177 void PushDeclaration( const char* value );
1178 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001179
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001180 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001181 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1182
1183 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1184 virtual bool VisitExit( const XMLElement& element );
1185
1186 virtual bool Visit( const XMLText& text );
1187 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001188 virtual bool Visit( const XMLDeclaration& declaration );
1189 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001190
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001191 /**
1192 If in print to memory mode, return a pointer to
1193 the XML file in memory.
1194 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001195 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001196
Lee Thomason5cae8972012-01-24 18:03:07 -08001197private:
1198 void SealElement();
1199 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001200 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001201 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001202
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001203 bool elementJustOpened;
1204 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001205 FILE* fp;
1206 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001207 int textDepth;
Lee Thomason6f381b72012-03-02 12:59:39 -08001208 bool processEntities;
Lee Thomason56bdd022012-02-09 18:16:58 -08001209
Lee Thomason857b8682012-01-25 17:50:25 -08001210 enum {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001211 ENTITY_RANGE = 64,
1212 BUF_SIZE = 200
Lee Thomason857b8682012-01-25 17:50:25 -08001213 };
1214 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001215 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001216
Lee Thomason2c85a712012-01-31 08:24:24 -08001217 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001218 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001219};
1220
1221
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001222} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001223
U-Lama\Lee560bd472011-12-28 19:42:49 -08001224
1225
U-Stream\Leeae25a442012-02-17 17:48:16 -08001226#endif // TINYXML2_INCLUDED