blob: b1fa008204d2a94e89c7d0c408a01c6475df8433 [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
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -070027#include <cctype>
28#include <climits>
29#include <cstdio>
30#include <cstring>
31#if __APPLE__
32# include <memory.h>
33#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080034
Lee Thomason7d00b9a2012-02-27 17:54:22 -080035/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080036 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080037 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080038*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080039/*
40 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
41*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080042
U-Lama\Lee4cee6112011-12-31 14:58:18 -080043#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
44 #ifndef DEBUG
45 #define DEBUG
46 #endif
47#endif
48
49
50#if defined(DEBUG)
51 #if defined(_MSC_VER)
52 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
53 #elif defined (ANDROID_NDK)
54 #include <android/log.h>
55 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
56 #else
57 #include <assert.h>
58 #define TIXMLASSERT assert
59 #endif
60#else
61 #define TIXMLASSERT( x ) {}
62#endif
63
U-Lama\Leee13c3e62011-12-28 14:36:55 -080064
Lee Thomason1a1d4a72012-02-15 09:09:25 -080065// Deprecated library function hell. Compilers want to use the
66// new safe versions. This probably doesn't fully address the problem,
67// but it gets closer. There are too many compilers for me to fully
68// test. If you get compilation troubles, undefine TIXML_SAFE
69
70#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
71 // Microsoft visual studio, version 2005 and higher.
72 #define TIXML_SNPRINTF _snprintf_s
73 #define TIXML_SSCANF sscanf_s
74#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
75 // Microsoft visual studio, version 6 and higher.
76 //#pragma message( "Using _sn* functions." )
77 #define TIXML_SNPRINTF _snprintf
78 #define TIXML_SSCANF sscanf
79#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080080 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081 //#warning( "Using sn* functions." )
82 #define TIXML_SNPRINTF snprintf
83 #define TIXML_SSCANF sscanf
84#else
85 #define TIXML_SNPRINTF snprintf
86 #define TIXML_SSCANF sscanf
87#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080088
Lee Thomason27057312012-03-02 09:04:53 -080089static const int TIXML2_MAJOR_VERSION = 0;
90static const int TIXML2_MINOR_VERSION = 9;
91static const int TIXML2_PATCH_VERSION = 0;
Lee Thomason1ff38e02012-02-14 18:18:16 -080092
U-Lama\Leee13c3e62011-12-28 14:36:55 -080093namespace tinyxml2
94{
Lee Thomasonce0763e2012-01-11 15:43:54 -080095class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080096class XMLElement;
97class XMLAttribute;
98class XMLComment;
99class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800100class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800101class XMLDeclaration;
102class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800103
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800104class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800105
U-Stream\Leeae25a442012-02-17 17:48:16 -0800106/*
107 A class that wraps strings. Normally stores the start and end
108 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800109 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800110 manage) a traditional char[]
111*/
Lee Thomason39ede242012-01-20 11:27:56 -0800112class StrPair
113{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800114public:
Lee Thomason39ede242012-01-20 11:27:56 -0800115 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800116 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800117 NEEDS_NEWLINE_NORMALIZATION = 0x02,
118
119 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800120 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800121 ATTRIBUTE_NAME = 0,
122 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800123 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700124 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800125 };
126
127 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128 ~StrPair();
129
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700130 void Set( char* start_, char* end_, int flags_ ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800131 Reset();
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700132 this->start = start_; this->end = end_; this->flags = flags_ | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800133 }
134 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800135 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800136
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
138 void SetStr( const char* str, int flags=0 );
139
Lee Thomason56bdd022012-02-09 18:16:58 -0800140 char* ParseText( char* in, const char* endTag, int strFlags );
141 char* ParseName( char* in );
142
Lee Thomason2c85a712012-01-31 08:24:24 -0800143
Lee Thomason39ede242012-01-20 11:27:56 -0800144private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800145 void Reset();
146
Lee Thomasone4422302012-01-20 17:59:50 -0800147 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148 NEEDS_FLUSH = 0x100,
149 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800150 };
151
Lee Thomason39ede242012-01-20 11:27:56 -0800152 // After parsing, if *end != 0, it can be set to zero.
153 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800154 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800155 char* end;
156};
157
U-Lama\Lee560bd472011-12-28 19:42:49 -0800158
U-Stream\Leeae25a442012-02-17 17:48:16 -0800159/*
160 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
161 Has a small initial memory pool, so that low or no usage will not
162 cause a call to new/delete
163*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800164template <class T, int INIT>
165class DynArray
166{
167public:
168 DynArray< T, INIT >()
169 {
170 mem = pool;
171 allocated = INIT;
172 size = 0;
173 }
174 ~DynArray()
175 {
176 if ( mem != pool ) {
177 delete mem;
178 }
179 }
180 void Push( T t )
181 {
182 EnsureCapacity( size+1 );
183 mem[size++] = t;
184 }
185
186 T* PushArr( int count )
187 {
188 EnsureCapacity( size+count );
189 T* ret = &mem[size];
190 size += count;
191 return ret;
192 }
193 T Pop() {
194 return mem[--size];
195 }
196 void PopArr( int count )
197 {
198 TIXMLASSERT( size >= count );
199 size -= count;
200 }
201
U-Stream\Leeae25a442012-02-17 17:48:16 -0800202 bool Empty() const { return size == 0; }
203 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
204 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
205 int Size() const { return size; }
206 int Capacity() const { return allocated; }
207 const T* Mem() const { return mem; }
208 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800209
210
211private:
212 void EnsureCapacity( int cap ) {
213 if ( cap > allocated ) {
214 int newAllocated = cap * 2;
215 T* newMem = new T[newAllocated];
216 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
217 if ( mem != pool ) delete [] mem;
218 mem = newMem;
219 allocated = newAllocated;
220 }
221 }
222
223 T* mem;
224 T pool[INIT];
225 int allocated; // objects allocated
226 int size; // number objects in use
227};
228
Lee Thomason50adb4c2012-02-13 15:07:09 -0800229
U-Stream\Leeae25a442012-02-17 17:48:16 -0800230/*
231 Parent virtual class a a pool for fast allocation
232 and deallocation of objects.
233*/
Lee Thomasond1983222012-02-06 08:41:24 -0800234class MemPool
235{
236public:
237 MemPool() {}
238 virtual ~MemPool() {}
239
240 virtual int ItemSize() const = 0;
241 virtual void* Alloc() = 0;
242 virtual void Free( void* ) = 0;
243};
244
Lee Thomason50adb4c2012-02-13 15:07:09 -0800245
U-Stream\Leeae25a442012-02-17 17:48:16 -0800246/*
247 Template child class to create pools of the correct type.
248*/
Lee Thomasond1983222012-02-06 08:41:24 -0800249template< int SIZE >
250class MemPoolT : public MemPool
251{
252public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800253 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800254 ~MemPoolT() {
255 // Delete the blocks.
256 for( int i=0; i<blockPtrs.Size(); ++i ) {
257 delete blockPtrs[i];
258 }
259 }
260
261 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800262 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800263
264 virtual void* Alloc() {
265 if ( !root ) {
266 // Need a new block.
267 Block* block = new Block();
268 blockPtrs.Push( block );
269
270 for( int i=0; i<COUNT-1; ++i ) {
271 block->chunk[i].next = &block->chunk[i+1];
272 }
273 block->chunk[COUNT-1].next = 0;
274 root = block->chunk;
275 }
276 void* result = root;
277 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800278
279 ++currentAllocs;
280 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
281 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800282 return result;
283 }
284 virtual void Free( void* mem ) {
285 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800286 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800287 Chunk* chunk = (Chunk*)mem;
288 memset( chunk, 0xfe, sizeof(Chunk) );
289 chunk->next = root;
290 root = chunk;
291 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800292 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800293 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
294 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800295 }
Lee Thomasond1983222012-02-06 08:41:24 -0800296
297private:
298 enum { COUNT = 1024/SIZE };
299 union Chunk {
300 Chunk* next;
301 char mem[SIZE];
302 };
303 struct Block {
304 Chunk chunk[COUNT];
305 };
306 DynArray< Block*, 10 > blockPtrs;
307 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800308
309 int currentAllocs;
310 int nAllocs;
311 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800312};
313
Lee Thomason2c85a712012-01-31 08:24:24 -0800314
Lee Thomason56bdd022012-02-09 18:16:58 -0800315
316/**
317 Implements the interface to the "Visitor pattern" (see the Accept() method.)
318 If you call the Accept() method, it requires being passed a XMLVisitor
319 class to handle callbacks. For nodes that contain other nodes (Document, Element)
320 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
321 are simply called with Visit().
322
323 If you return 'true' from a Visit method, recursive parsing will continue. If you return
324 false, <b>no children of this node or its sibilings</b> will be Visited.
325
326 All flavors of Visit methods have a default implementation that returns 'true' (continue
327 visiting). You need to only override methods that are interesting to you.
328
329 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
330
331 You should never change the document from a callback.
332
333 @sa XMLNode::Accept()
334*/
335class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800336{
337public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800338 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800339
Lee Thomason56bdd022012-02-09 18:16:58 -0800340 /// Visit a document.
341 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
342 /// Visit a document.
343 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
344
345 /// Visit an element.
346 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
347 /// Visit an element.
348 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
349
350 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800351 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800352 /// Visit a text node
353 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
354 /// Visit a comment node
355 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
356 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800357 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800358};
359
360
U-Stream\Leeae25a442012-02-17 17:48:16 -0800361/*
362 Utility functionality.
363*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800364class XMLUtil
365{
Lee Thomasond1983222012-02-06 08:41:24 -0800366public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800367 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
368 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800369 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
370 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800371
372 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
373 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800374 if ( p == q ) {
375 return true;
376 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800377 while( *p && *q && *p == *q && n<nChar ) {
378 ++p; ++q; ++n;
379 }
380 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
381 return true;
382 }
383 return false;
384 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700385 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800386 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
387 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800388
389 static const char* ReadBOM( const char* p, bool* hasBOM );
390 // p is the starting location,
391 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800392 static const char* GetCharacterRef( const char* p, char* value, int* length );
393 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800394};
395
Lee Thomason5cae8972012-01-24 18:03:07 -0800396
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800397/** XMLNode is a base class for every object that is in the
398 XML Document Object Model (DOM), except XMLAttributes.
399 Nodes have siblings, a parent, and children which can
400 be navigated. A node is always in a XMLDocument.
401 The type of a TiXmlNode can be queried, and it can
402 be cast to its more defined type.
403
404 An XMLDocument allocates memory for all its Nodes.
405 When the XMLDocument gets deleted, all its Nodes
406 will also be deleted.
407
408 @verbatim
409 A Document can contain: Element (container or leaf)
410 Comment (leaf)
411 Unknown (leaf)
412 Declaration( leaf )
413
414 An Element can contain: Element (container or leaf)
415 Text (leaf)
416 Attributes (not on tree)
417 Comment (leaf)
418 Unknown (leaf)
419
420 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800421*/
Lee Thomasond1983222012-02-06 08:41:24 -0800422class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800423{
424 friend class XMLDocument;
425 friend class XMLElement;
426public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800427
428 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800429 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800430 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800431 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800432
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800433 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
434 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
435 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
436 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
437 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
438 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800439
Lee Thomason50f97b22012-02-11 16:33:40 -0800440 virtual const XMLElement* ToElement() const { return 0; }
441 virtual const XMLText* ToText() const { return 0; }
442 virtual const XMLComment* ToComment() const { return 0; }
443 virtual const XMLDocument* ToDocument() const { return 0; }
444 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
445 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800446
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800447 /** The meaning of 'value' changes for the specific type.
448 @verbatim
449 Document: empy
450 Element: name of the element
451 Comment: the comment text
452 Unknown: the tag contents
453 Text: the text string
454 @endverbatim
455 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800456 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800457 /** Set the Value of an XML node.
458 @sa Value()
459 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800460 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800461
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800462 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800463 const XMLNode* Parent() const { return parent; }
464 XMLNode* Parent() { return parent; }
465
Lee Thomason50f97b22012-02-11 16:33:40 -0800466 /// Returns true if this node has no children.
467 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800468
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800469 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800470 const XMLNode* FirstChild() const { return firstChild; }
471 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800472 /** Get the first child element, or optionally the first child
473 element with the specified name.
474 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800475 const XMLElement* FirstChildElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700476 XMLElement* FirstChildElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value_ )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800477
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800478 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800479 const XMLNode* LastChild() const { return lastChild; }
480 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800481
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800482 /** Get the last child element or optionally the last child
483 element with the specified name.
484 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800485 const XMLElement* LastChildElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700486 XMLElement* LastChildElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value_) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800487
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800488 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800489 const XMLNode* PreviousSibling() const { return prev; }
490 XMLNode* PreviousSibling() { return prev; }
491
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800492 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800493 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700494 XMLElement* PreviousSiblingElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value_ ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800495
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800496 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800497 const XMLNode* NextSibling() const { return next; }
498 XMLNode* NextSibling() { return next; }
499
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800500 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800501 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700502 XMLElement* NextSiblingElement( const char* value_=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value_ ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800503
Lee Thomason1ff38e02012-02-14 18:18:16 -0800504 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800505 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800506 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800507 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800508
509 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800510 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800511 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800512 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800513 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800514 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800515 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800516 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800517 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
518
U-Stream\Leeae25a442012-02-17 17:48:16 -0800519 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800520 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800521 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800522 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800523
524 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800525 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800526 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800527 void DeleteChild( XMLNode* node );
528
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529 /**
530 Make a copy of this node, but not its children.
531 You may pass in a Document pointer that will be
532 the owner of the new Node. If the 'document' is
533 null, then the node returned will be allocated
534 from the current Document. (this->GetDocument())
535
536 Note: if called on a XMLDocument, this will return null.
537 */
538 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
539
540 /**
541 Test if 2 nodes are the same, but don't test children.
542 The 2 nodes do not need to be in the same Document.
543
544 Note: if called on a XMLDocument, this will return false.
545 */
546 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
547
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800548 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
549 XML tree will be conditionally visited and the host will be called back
550 via the TiXmlVisitor interface.
551
552 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
553 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
554 interface versus any other.)
555
556 The interface has been based on ideas from:
557
558 - http://www.saxproject.org/
559 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
560
561 Which are both good references for "visiting".
562
563 An example of using Accept():
564 @verbatim
565 TiXmlPrinter printer;
566 tinyxmlDoc.Accept( &printer );
567 const char* xmlcstr = printer.CStr();
568 @endverbatim
569 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800570 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800571
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800572 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800573 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800574
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800575protected:
576 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800577 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800578 XMLNode( const XMLNode& ); // not supported
579 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800580
Lee Thomason3f57d272012-01-11 15:30:03 -0800581 XMLDocument* document;
582 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800583 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800584
585 XMLNode* firstChild;
586 XMLNode* lastChild;
587
588 XMLNode* prev;
589 XMLNode* next;
590
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800591private:
Lee Thomasond1983222012-02-06 08:41:24 -0800592 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800593 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800594};
595
596
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800597/** XML text.
598
599 Note that a text node can have child element nodes, for example:
600 @verbatim
601 <root>This is <b>bold</b></root>
602 @endverbatim
603
604 A text node can have 2 ways to output the next. "normal" output
605 and CDATA. It will default to the mode it was parsed from the XML file and
606 you generally want to leave it alone, but you can change the output mode with
607 SetCDATA() and query it with CDATA().
608*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800609class XMLText : public XMLNode
610{
Lee Thomason2c85a712012-01-31 08:24:24 -0800611 friend class XMLBase;
612 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800613public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800614 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800615
Lee Thomason751da522012-02-10 08:50:51 -0800616 virtual XMLText* ToText() { return this; }
617 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800618
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800619 /// Declare whether this should be CDATA or standard text.
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700620 void SetCData( bool isCData_ ) { this->isCData = isCData_; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800621 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800622 bool CData() const { return isCData; }
623
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800624 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800625 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
626 virtual bool ShallowEqual( const XMLNode* compare ) const;
627
Lee Thomason5492a1c2012-01-23 15:32:10 -0800628
629protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800630 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
631 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800632 XMLText( const XMLText& ); // not supported
633 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800634
635private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800636 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800637};
638
639
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800640/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800641class XMLComment : public XMLNode
642{
Lee Thomason2c85a712012-01-31 08:24:24 -0800643 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800644public:
Lee Thomason751da522012-02-10 08:50:51 -0800645 virtual XMLComment* ToComment() { return this; }
646 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800647
Lee Thomason56bdd022012-02-09 18:16:58 -0800648 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800649
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800650 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800651 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
652 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800653
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800655 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800656 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800657 XMLComment( const XMLComment& ); // not supported
658 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason3f57d272012-01-11 15:30:03 -0800660private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800661};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800662
663
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800664/** In correct XML the declaration is the first entry in the file.
665 @verbatim
666 <?xml version="1.0" standalone="yes"?>
667 @endverbatim
668
669 TinyXML2 will happily read or write files without a declaration,
670 however.
671
672 The text of the declaration isn't interpreted. It is parsed
673 and written as a string.
674*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800675class XMLDeclaration : public XMLNode
676{
677 friend class XMLDocument;
678public:
679 virtual XMLDeclaration* ToDeclaration() { return this; }
680 virtual const XMLDeclaration* ToDeclaration() const { return this; }
681
682 virtual bool Accept( XMLVisitor* visitor ) const;
683
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800684 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800685 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
686 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800687
688protected:
689 XMLDeclaration( XMLDocument* doc );
690 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800691 XMLDeclaration( const XMLDeclaration& ); // not supported
692 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800693};
694
695
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800696/** Any tag that tinyXml doesn't recognize is saved as an
697 unknown. It is a tag of text, but should not be modified.
698 It will be written back to the XML, unchanged, when the file
699 is saved.
700
701 DTD tags get thrown into TiXmlUnknowns.
702*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800703class XMLUnknown : public XMLNode
704{
705 friend class XMLDocument;
706public:
707 virtual XMLUnknown* ToUnknown() { return this; }
708 virtual const XMLUnknown* ToUnknown() const { return this; }
709
710 virtual bool Accept( XMLVisitor* visitor ) const;
711
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800712 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800713 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
714 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800715
716protected:
717 XMLUnknown( XMLDocument* doc );
718 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800719 XMLUnknown( const XMLUnknown& ); // not supported
720 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800721};
722
723
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800725 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800726 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800727
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700728 XML_NO_ATTRIBUTE,
729 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800730
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700731 XML_ERROR_FILE_NOT_FOUND,
732 XML_ERROR_ELEMENT_MISMATCH,
733 XML_ERROR_PARSING_ELEMENT,
734 XML_ERROR_PARSING_ATTRIBUTE,
735 XML_ERROR_IDENTIFYING_TAG,
736 XML_ERROR_PARSING_TEXT,
737 XML_ERROR_PARSING_CDATA,
738 XML_ERROR_PARSING_COMMENT,
739 XML_ERROR_PARSING_DECLARATION,
740 XML_ERROR_PARSING_UNKNOWN,
741 XML_ERROR_EMPTY_DOCUMENT,
742 XML_ERROR_MISMATCHED_ELEMENT,
743 XML_ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800744};
745
746
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800747/** An attribute is a name-value pair. Elements have an arbitrary
748 number of attributes, each with a unique name.
749
750 @note The attributes are not XMLNodes. You may only query the
751 Next() attribute in a list.
752*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800753class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800754{
755 friend class XMLElement;
756public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800757 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
758 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
759 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800760
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800761 /** IntAttribute interprets the attribute as an integer, and returns the value.
762 If the value isn't an integer, 0 will be returned. There is no error checking;
763 use QueryIntAttribute() if you need error checking.
764 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800765 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800766 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800767 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800768 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800769 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800770 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800771 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800772 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800773 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800774
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800775 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
776 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700777 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800778 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800779 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800780 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800782 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800783 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800784 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800785 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800786 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800787 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800788
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800789 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800790 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800791 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800792 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800794 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800795 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800796 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800797 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800798 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800799 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800800 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800801
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800802private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800803 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800804
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800805 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800806 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800807 XMLAttribute( const XMLAttribute& ); // not supported
808 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800809 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800810
Lee Thomason6f381b72012-03-02 12:59:39 -0800811 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800812
Lee Thomason751da522012-02-10 08:50:51 -0800813 mutable StrPair name;
814 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800815 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800816 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800817};
818
819
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800820/** The element is a container class. It has a value, the element name,
821 and can contain other elements, text, comments, and unknowns.
822 Elements also contain an arbitrary number of attributes.
823*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824class XMLElement : public XMLNode
825{
Lee Thomason2c85a712012-01-31 08:24:24 -0800826 friend class XMLBase;
827 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800828public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800829 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800830 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800831 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800832 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800833
Lee Thomason751da522012-02-10 08:50:51 -0800834 virtual XMLElement* ToElement() { return this; }
835 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800836 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800837
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800838 /** Given an attribute name, Attribute() returns the value
839 for the attribute of that name, or null if none exists.
840 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800841 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 -0800842
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800843 /** Given an attribute name, IntAttribute() returns the value
844 of the attribute interpreted as an integer. 0 will be
845 returned if there is an error. For a method with error
846 checking, see QueryIntAttribute()
847 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800848 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800849 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800850 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800851 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800852 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800853 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800854 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800855 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800856 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
857
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800858 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700859 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
860 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800861 doesn't exist. If successful, the result of the conversion
862 will be written to 'value'. If not successful, nothing will
863 be written to 'value'. This allows you to provide default
864 value:
865
866 @verbatim
867 int value = 10;
868 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
869 @endverbatim
870 */
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700871 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 -0800872 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700873 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 -0800874 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700875 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 -0800876 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700877 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 -0800878 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700879 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 -0800880
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800881 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800882 void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800883 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800884 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800885 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800886 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800887 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800888 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800889 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800890 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800891
U-Stream\Leeae25a442012-02-17 17:48:16 -0800892 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800893 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800894 */
895 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800896
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800897 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800898 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800899 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800900 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800901
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800902 /** Convenience function for easy access to the text inside an element. Although easy
903 and concise, GetText() is limited compared to getting the TiXmlText child
904 and accessing it directly.
905
906 If the first child of 'this' is a TiXmlText, the GetText()
907 returns the character string of the Text node, else null is returned.
908
909 This is a convenient method for getting the text of simple contained text:
910 @verbatim
911 <foo>This is text</foo>
912 const char* str = fooElement->GetText();
913 @endverbatim
914
915 'str' will be a pointer to "This is text".
916
917 Note that this function can be misleading. If the element foo was created from
918 this XML:
919 @verbatim
920 <foo><b>This is text</b></foo>
921 @endverbatim
922
923 then the value of str would be null. The first child node isn't a text node, it is
924 another element. From this XML:
925 @verbatim
926 <foo>This is <b>text</b></foo>
927 @endverbatim
928 GetText() will return "This is ".
929 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800930 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800931
Lee Thomason2c85a712012-01-31 08:24:24 -0800932 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800933 enum {
934 OPEN, // <foo>
935 CLOSED, // <foo/>
936 CLOSING // </foo>
937 };
938 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800939 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
941 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800942
Lee Thomason50adb4c2012-02-13 15:07:09 -0800943private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800944 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800945 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800946 XMLElement( const XMLElement& ); // not supported
947 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800948
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800949 XMLAttribute* FindAttribute( const char* name );
950 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800951 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800952 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800953
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800955 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800956};
957
958
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800959/** A document binds together all the functionality.
960 It can be saved, loaded, and printed to the screen.
961 All Nodes are connected and allocated to a Document.
962 If the Document is deleted, all its Nodes are also deleted.
963*/
Lee Thomason67d61312012-01-24 16:01:51 -0800964class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800965{
Lee Thomasond1983222012-02-06 08:41:24 -0800966 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800967public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800968 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -0800969 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -0800970 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800971
Lee Thomason751da522012-02-10 08:50:51 -0800972 virtual XMLDocument* ToDocument() { return this; }
973 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800974
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800975 /**
976 Parse an XML file from a character string.
977 Returns XML_NO_ERROR (0) on success, or
978 an errorID.
979 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800980 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800981 /**
982 Load an XML file from disk.
983 Returns XML_NO_ERROR (0) on success, or
984 an errorID.
985 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800986 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800987 /**
988 Load an XML file from disk. You are responsible
989 for providing and closing the FILE*.
990
991 Returns XML_NO_ERROR (0) on success, or
992 an errorID.
993 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800994 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800995 /**
996 Save the XML file to disk.
997 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800998 void SaveFile( const char* filename );
999
Lee Thomason6f381b72012-03-02 12:59:39 -08001000 bool ProcessEntities() const { return processEntities; }
1001
1002 /**
1003 Returns true if this document has a leading Byte Order Mark of UTF8.
1004 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001005 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001006
1007 /** Return the root element of DOM. Equivalent to FirstChildElement().
1008 To get the first node, use FirstChild().
1009 */
Lee Thomasond6277762012-02-22 16:00:12 -08001010 XMLElement* RootElement() { return FirstChildElement(); }
1011 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001012
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001013 /** Print the Document. If the Printer is not provided, it will
1014 print to stdout. If you provide Printer, this can print to a file:
1015 @verbatim
1016 XMLPrinter printer( fp );
1017 doc.Print( &printer );
1018 @endverbatim
1019
1020 Or you can use a printer to print to memory:
1021 @verbatim
1022 XMLPrinter printer;
1023 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001024 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001025 @endverbatim
1026 */
1027 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001028 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001029
Lee Thomason1ff38e02012-02-14 18:18:16 -08001030 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001031 Create a new Element associated with
1032 this Document. The memory for the Element
1033 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001034 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001035 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001036 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001037 Create a new Comment associated with
1038 this Document. The memory for the Comment
1039 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001040 */
1041 XMLComment* NewComment( const char* comment );
1042 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001043 Create a new Text associated with
1044 this Document. The memory for the Text
1045 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001046 */
1047 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001048 /**
1049 Create a new Declaration associated with
1050 this Document. The memory for the object
1051 is managed by the Document.
1052 */
1053 XMLDeclaration* NewDeclaration( const char* text );
1054 /**
1055 Create a new Unknown associated with
1056 this Document. The memory for the object
1057 is managed by the Document.
1058 */
1059 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001060
U-Stream\Leeae25a442012-02-17 17:48:16 -08001061 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001062 Delete a node associated with this documented.
1063 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001064 */
1065 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1066
Lee Thomason67d61312012-01-24 16:01:51 -08001067 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001068
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001069 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001070 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001071 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001072 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001073 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001074 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001075 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001076 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001077 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001078 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001080 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001081 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001082
Lee Thomason6f381b72012-03-02 12:59:39 -08001083 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1084 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001085
Lee Thomason3f57d272012-01-11 15:30:03 -08001086private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001087 XMLDocument( const XMLDocument& ); // not supported
1088 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001089 void InitDocument();
1090
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001091 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001092 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001093 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001094 const char* errorStr1;
1095 const char* errorStr2;
1096 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001097
1098 MemPoolT< sizeof(XMLElement) > elementPool;
1099 MemPoolT< sizeof(XMLAttribute) > attributePool;
1100 MemPoolT< sizeof(XMLText) > textPool;
1101 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001102};
1103
Lee Thomason7c913cd2012-01-26 18:32:34 -08001104
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001105
1106/**
1107 Printing functionality. The XMLPrinter gives you more
1108 options than the XMLDocument::Print() method.
1109
1110 It can:
1111 -# Print to memory.
1112 -# Print to a file you provide
1113 -# Print XML without a XMLDocument.
1114
1115 Print to Memory
1116
1117 @verbatim
1118 XMLPrinter printer;
1119 doc->Print( &printer );
1120 SomeFunctior( printer.CStr() );
1121 @endverbatim
1122
1123 Print to a File
1124
1125 You provide the file pointer.
1126 @verbatim
1127 XMLPrinter printer( fp );
1128 doc.Print( &printer );
1129 @endverbatim
1130
1131 Print without a XMLDocument
1132
1133 When loading, an XML parser is very useful. However, sometimes
1134 when saving, it just gets in the way. The code is often set up
1135 for streaming, and constructing the DOM is just overhead.
1136
1137 The Printer supports the streaming case. The following code
1138 prints out a trivially simple XML file without ever creating
1139 an XML document.
1140
1141 @verbatim
1142 XMLPrinter printer( fp );
1143 printer.OpenElement( "foo" );
1144 printer.PushAttribute( "foo", "bar" );
1145 printer.CloseElement();
1146 @endverbatim
1147*/
1148class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001149{
1150public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001151 /** Construct the printer. If the FILE* is specified,
1152 this will print to the FILE. Else it will print
1153 to memory, and the result is available in CStr()
1154 */
1155 XMLPrinter( FILE* file=0 );
1156 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001157
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001158 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001159 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001160 /** If streaming, start writing an element.
1161 The element must be closed with CloseElement()
1162 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001163 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001164 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001165 void PushAttribute( const char* name, const char* value );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001166 void PushAttribute( const char* name, int value );
1167 void PushAttribute( const char* name, unsigned value );
1168 void PushAttribute( const char* name, bool value );
1169 void PushAttribute( const char* name, double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001170 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001171 void CloseElement();
1172
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001173 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001174 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001175 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001176 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001177
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001178 void PushDeclaration( const char* value );
1179 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001180
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001181 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001182 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1183
1184 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1185 virtual bool VisitExit( const XMLElement& element );
1186
1187 virtual bool Visit( const XMLText& text );
1188 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001189 virtual bool Visit( const XMLDeclaration& declaration );
1190 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001191
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001192 /**
1193 If in print to memory mode, return a pointer to
1194 the XML file in memory.
1195 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001196 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001197
Lee Thomason5cae8972012-01-24 18:03:07 -08001198private:
1199 void SealElement();
1200 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001201 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001202 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001203
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001204 bool elementJustOpened;
1205 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001206 FILE* fp;
1207 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001208 int textDepth;
Lee Thomason6f381b72012-03-02 12:59:39 -08001209 bool processEntities;
Lee Thomason56bdd022012-02-09 18:16:58 -08001210
Lee Thomason857b8682012-01-25 17:50:25 -08001211 enum {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212 ENTITY_RANGE = 64,
1213 BUF_SIZE = 200
Lee Thomason857b8682012-01-25 17:50:25 -08001214 };
1215 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001216 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001217
Lee Thomason2c85a712012-01-31 08:24:24 -08001218 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001219 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001220};
1221
1222
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001223} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001224
U-Lama\Lee560bd472011-12-28 19:42:49 -08001225
1226
U-Stream\Leeae25a442012-02-17 17:48:16 -08001227#endif // TINYXML2_INCLUDED