blob: f5c253d5f4704fcccd32c16820dc4501c3a0dc26 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
Lee Thomason7d00b9a2012-02-27 17:54:22 -080024#ifndef TINYXML2_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025#define TINYXML2_INCLUDED
26
Lee Thomason5ce89412012-03-20 13:23:44 -070027#if 1
28 #include <cctype>
29 #include <climits>
30 #include <cstdio>
31 #include <cstring>
32#else
33 // Not completely sure all the interesting systems
34 // can handle the new headers; can switch this if
35 // there is an include problem.
36 #include <limits.h>
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <memory.h> // Needed by mac.
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -070040#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080041
Lee Thomason7d00b9a2012-02-27 17:54:22 -080042/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080043 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080044 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080045*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080046/*
47 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
48*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080049
U-Lama\Lee4cee6112011-12-31 14:58:18 -080050#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
51 #ifndef DEBUG
52 #define DEBUG
53 #endif
54#endif
55
56
57#if defined(DEBUG)
58 #if defined(_MSC_VER)
59 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
60 #elif defined (ANDROID_NDK)
61 #include <android/log.h>
62 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
63 #else
64 #include <assert.h>
65 #define TIXMLASSERT assert
66 #endif
67#else
68 #define TIXMLASSERT( x ) {}
69#endif
70
U-Lama\Leee13c3e62011-12-28 14:36:55 -080071
Lee Thomason1a1d4a72012-02-15 09:09:25 -080072// Deprecated library function hell. Compilers want to use the
73// new safe versions. This probably doesn't fully address the problem,
74// but it gets closer. There are too many compilers for me to fully
75// test. If you get compilation troubles, undefine TIXML_SAFE
76
77#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
78 // Microsoft visual studio, version 2005 and higher.
79 #define TIXML_SNPRINTF _snprintf_s
80 #define TIXML_SSCANF sscanf_s
81#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
82 // Microsoft visual studio, version 6 and higher.
83 //#pragma message( "Using _sn* functions." )
84 #define TIXML_SNPRINTF _snprintf
85 #define TIXML_SSCANF sscanf
86#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080087 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080088 //#warning( "Using sn* functions." )
89 #define TIXML_SNPRINTF snprintf
90 #define TIXML_SSCANF sscanf
91#else
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_SSCANF sscanf
94#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080095
Lee Thomason27057312012-03-02 09:04:53 -080096static const int TIXML2_MAJOR_VERSION = 0;
97static const int TIXML2_MINOR_VERSION = 9;
98static const int TIXML2_PATCH_VERSION = 0;
Lee Thomason1ff38e02012-02-14 18:18:16 -080099
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800100namespace tinyxml2
101{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800102class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800103class XMLElement;
104class XMLAttribute;
105class XMLComment;
106class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800107class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800108class XMLDeclaration;
109class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800110
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800111class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800112
U-Stream\Leeae25a442012-02-17 17:48:16 -0800113/*
114 A class that wraps strings. Normally stores the start and end
115 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800116 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800117 manage) a traditional char[]
118*/
Lee Thomason39ede242012-01-20 11:27:56 -0800119class StrPair
120{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800121public:
Lee Thomason39ede242012-01-20 11:27:56 -0800122 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800123 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800124 NEEDS_NEWLINE_NORMALIZATION = 0x02,
125
126 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800127 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800128 ATTRIBUTE_NAME = 0,
129 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800130 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700131 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800132 };
133
134 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135 ~StrPair();
136
Lee Thomason5ce89412012-03-20 13:23:44 -0700137 void Set( char* _start, char* _end, int _flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138 Reset();
Lee Thomason5ce89412012-03-20 13:23:44 -0700139 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800140 }
141 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800142 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800143
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800144 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
145 void SetStr( const char* str, int flags=0 );
146
Lee Thomason56bdd022012-02-09 18:16:58 -0800147 char* ParseText( char* in, const char* endTag, int strFlags );
148 char* ParseName( char* in );
149
Lee Thomason2c85a712012-01-31 08:24:24 -0800150
Lee Thomason39ede242012-01-20 11:27:56 -0800151private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152 void Reset();
153
Lee Thomasone4422302012-01-20 17:59:50 -0800154 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155 NEEDS_FLUSH = 0x100,
156 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800157 };
158
Lee Thomason39ede242012-01-20 11:27:56 -0800159 // After parsing, if *end != 0, it can be set to zero.
160 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800161 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800162 char* end;
163};
164
U-Lama\Lee560bd472011-12-28 19:42:49 -0800165
U-Stream\Leeae25a442012-02-17 17:48:16 -0800166/*
167 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
168 Has a small initial memory pool, so that low or no usage will not
169 cause a call to new/delete
170*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800171template <class T, int INIT>
172class DynArray
173{
174public:
175 DynArray< T, INIT >()
176 {
177 mem = pool;
178 allocated = INIT;
179 size = 0;
180 }
181 ~DynArray()
182 {
183 if ( mem != pool ) {
184 delete mem;
185 }
186 }
187 void Push( T t )
188 {
189 EnsureCapacity( size+1 );
190 mem[size++] = t;
191 }
192
193 T* PushArr( int count )
194 {
195 EnsureCapacity( size+count );
196 T* ret = &mem[size];
197 size += count;
198 return ret;
199 }
200 T Pop() {
201 return mem[--size];
202 }
203 void PopArr( int count )
204 {
205 TIXMLASSERT( size >= count );
206 size -= count;
207 }
208
U-Stream\Leeae25a442012-02-17 17:48:16 -0800209 bool Empty() const { return size == 0; }
210 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
211 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
212 int Size() const { return size; }
213 int Capacity() const { return allocated; }
214 const T* Mem() const { return mem; }
215 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800216
217
218private:
219 void EnsureCapacity( int cap ) {
220 if ( cap > allocated ) {
221 int newAllocated = cap * 2;
222 T* newMem = new T[newAllocated];
223 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
224 if ( mem != pool ) delete [] mem;
225 mem = newMem;
226 allocated = newAllocated;
227 }
228 }
229
230 T* mem;
231 T pool[INIT];
232 int allocated; // objects allocated
233 int size; // number objects in use
234};
235
Lee Thomason50adb4c2012-02-13 15:07:09 -0800236
U-Stream\Leeae25a442012-02-17 17:48:16 -0800237/*
238 Parent virtual class a a pool for fast allocation
239 and deallocation of objects.
240*/
Lee Thomasond1983222012-02-06 08:41:24 -0800241class MemPool
242{
243public:
244 MemPool() {}
245 virtual ~MemPool() {}
246
247 virtual int ItemSize() const = 0;
248 virtual void* Alloc() = 0;
249 virtual void Free( void* ) = 0;
250};
251
Lee Thomason50adb4c2012-02-13 15:07:09 -0800252
U-Stream\Leeae25a442012-02-17 17:48:16 -0800253/*
254 Template child class to create pools of the correct type.
255*/
Lee Thomasond1983222012-02-06 08:41:24 -0800256template< int SIZE >
257class MemPoolT : public MemPool
258{
259public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800260 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800261 ~MemPoolT() {
262 // Delete the blocks.
263 for( int i=0; i<blockPtrs.Size(); ++i ) {
264 delete blockPtrs[i];
265 }
266 }
267
268 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800269 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800270
271 virtual void* Alloc() {
272 if ( !root ) {
273 // Need a new block.
274 Block* block = new Block();
275 blockPtrs.Push( block );
276
277 for( int i=0; i<COUNT-1; ++i ) {
278 block->chunk[i].next = &block->chunk[i+1];
279 }
280 block->chunk[COUNT-1].next = 0;
281 root = block->chunk;
282 }
283 void* result = root;
284 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800285
286 ++currentAllocs;
287 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
288 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800289 return result;
290 }
291 virtual void Free( void* mem ) {
292 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800293 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800294 Chunk* chunk = (Chunk*)mem;
295 memset( chunk, 0xfe, sizeof(Chunk) );
296 chunk->next = root;
297 root = chunk;
298 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800299 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800300 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
301 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800302 }
Lee Thomasond1983222012-02-06 08:41:24 -0800303
304private:
305 enum { COUNT = 1024/SIZE };
306 union Chunk {
307 Chunk* next;
308 char mem[SIZE];
309 };
310 struct Block {
311 Chunk chunk[COUNT];
312 };
313 DynArray< Block*, 10 > blockPtrs;
314 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800315
316 int currentAllocs;
317 int nAllocs;
318 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800319};
320
Lee Thomason2c85a712012-01-31 08:24:24 -0800321
Lee Thomason56bdd022012-02-09 18:16:58 -0800322
323/**
324 Implements the interface to the "Visitor pattern" (see the Accept() method.)
325 If you call the Accept() method, it requires being passed a XMLVisitor
326 class to handle callbacks. For nodes that contain other nodes (Document, Element)
327 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
328 are simply called with Visit().
329
330 If you return 'true' from a Visit method, recursive parsing will continue. If you return
331 false, <b>no children of this node or its sibilings</b> will be Visited.
332
333 All flavors of Visit methods have a default implementation that returns 'true' (continue
334 visiting). You need to only override methods that are interesting to you.
335
336 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
337
338 You should never change the document from a callback.
339
340 @sa XMLNode::Accept()
341*/
342class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800343{
344public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800345 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800346
Lee Thomason56bdd022012-02-09 18:16:58 -0800347 /// Visit a document.
348 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
349 /// Visit a document.
350 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
351
352 /// Visit an element.
353 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
354 /// Visit an element.
355 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
356
357 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800358 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800359 /// Visit a text node
360 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
361 /// Visit a comment node
362 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
363 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800364 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800365};
366
367
U-Stream\Leeae25a442012-02-17 17:48:16 -0800368/*
369 Utility functionality.
370*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800371class XMLUtil
372{
Lee Thomasond1983222012-02-06 08:41:24 -0800373public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800374 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
375 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800376 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
377 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800378
379 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
380 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800381 if ( p == q ) {
382 return true;
383 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800384 while( *p && *q && *p == *q && n<nChar ) {
385 ++p; ++q; ++n;
386 }
387 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
388 return true;
389 }
390 return false;
391 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700392 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800393 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
394 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800395
396 static const char* ReadBOM( const char* p, bool* hasBOM );
397 // p is the starting location,
398 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800399 static const char* GetCharacterRef( const char* p, char* value, int* length );
400 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800401};
402
Lee Thomason5cae8972012-01-24 18:03:07 -0800403
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800404/** XMLNode is a base class for every object that is in the
405 XML Document Object Model (DOM), except XMLAttributes.
406 Nodes have siblings, a parent, and children which can
407 be navigated. A node is always in a XMLDocument.
408 The type of a TiXmlNode can be queried, and it can
409 be cast to its more defined type.
410
411 An XMLDocument allocates memory for all its Nodes.
412 When the XMLDocument gets deleted, all its Nodes
413 will also be deleted.
414
415 @verbatim
416 A Document can contain: Element (container or leaf)
417 Comment (leaf)
418 Unknown (leaf)
419 Declaration( leaf )
420
421 An Element can contain: Element (container or leaf)
422 Text (leaf)
423 Attributes (not on tree)
424 Comment (leaf)
425 Unknown (leaf)
426
427 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800428*/
Lee Thomasond1983222012-02-06 08:41:24 -0800429class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800430{
431 friend class XMLDocument;
432 friend class XMLElement;
433public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800434
435 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800436 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800437 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800438 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800439
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800440 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
441 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
442 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
443 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
444 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
445 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800446
Lee Thomason50f97b22012-02-11 16:33:40 -0800447 virtual const XMLElement* ToElement() const { return 0; }
448 virtual const XMLText* ToText() const { return 0; }
449 virtual const XMLComment* ToComment() const { return 0; }
450 virtual const XMLDocument* ToDocument() const { return 0; }
451 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
452 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800453
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800454 /** The meaning of 'value' changes for the specific type.
455 @verbatim
456 Document: empy
457 Element: name of the element
458 Comment: the comment text
459 Unknown: the tag contents
460 Text: the text string
461 @endverbatim
462 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800463 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800464 /** Set the Value of an XML node.
465 @sa Value()
466 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800467 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800468
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800469 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800470 const XMLNode* Parent() const { return parent; }
471 XMLNode* Parent() { return parent; }
472
Lee Thomason50f97b22012-02-11 16:33:40 -0800473 /// Returns true if this node has no children.
474 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800475
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800476 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800477 const XMLNode* FirstChild() const { return firstChild; }
478 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800479 /** Get the first child element, or optionally the first child
480 element with the specified name.
481 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800482 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700483 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800484
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800485 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800486 const XMLNode* LastChild() const { return lastChild; }
487 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800488
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800489 /** Get the last child element or optionally the last child
490 element with the specified name.
491 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800492 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700493 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800494
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800495 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800496 const XMLNode* PreviousSibling() const { return prev; }
497 XMLNode* PreviousSibling() { return prev; }
498
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800499 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800500 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason5ce89412012-03-20 13:23:44 -0700501 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800502
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800503 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800504 const XMLNode* NextSibling() const { return next; }
505 XMLNode* NextSibling() { return next; }
506
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800507 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800508 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700509 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800510
Lee Thomason1ff38e02012-02-14 18:18:16 -0800511 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800512 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800513 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800514 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800515
516 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800517 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800518 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800519 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800520 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800521 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800522 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800523 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800524 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
525
U-Stream\Leeae25a442012-02-17 17:48:16 -0800526 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800527 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800528 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800529 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800530
531 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800532 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800533 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800534 void DeleteChild( XMLNode* node );
535
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800536 /**
537 Make a copy of this node, but not its children.
538 You may pass in a Document pointer that will be
539 the owner of the new Node. If the 'document' is
540 null, then the node returned will be allocated
541 from the current Document. (this->GetDocument())
542
543 Note: if called on a XMLDocument, this will return null.
544 */
545 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
546
547 /**
548 Test if 2 nodes are the same, but don't test children.
549 The 2 nodes do not need to be in the same Document.
550
551 Note: if called on a XMLDocument, this will return false.
552 */
553 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
554
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800555 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
556 XML tree will be conditionally visited and the host will be called back
557 via the TiXmlVisitor interface.
558
559 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
560 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
561 interface versus any other.)
562
563 The interface has been based on ideas from:
564
565 - http://www.saxproject.org/
566 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
567
568 Which are both good references for "visiting".
569
570 An example of using Accept():
571 @verbatim
572 TiXmlPrinter printer;
573 tinyxmlDoc.Accept( &printer );
574 const char* xmlcstr = printer.CStr();
575 @endverbatim
576 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800577 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800578
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800579 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800580 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800581
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800582protected:
583 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800584 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800585 XMLNode( const XMLNode& ); // not supported
586 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800587
Lee Thomason3f57d272012-01-11 15:30:03 -0800588 XMLDocument* document;
589 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800590 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800591
592 XMLNode* firstChild;
593 XMLNode* lastChild;
594
595 XMLNode* prev;
596 XMLNode* next;
597
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800598private:
Lee Thomasond1983222012-02-06 08:41:24 -0800599 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800601};
602
603
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800604/** XML text.
605
606 Note that a text node can have child element nodes, for example:
607 @verbatim
608 <root>This is <b>bold</b></root>
609 @endverbatim
610
611 A text node can have 2 ways to output the next. "normal" output
612 and CDATA. It will default to the mode it was parsed from the XML file and
613 you generally want to leave it alone, but you can change the output mode with
614 SetCDATA() and query it with CDATA().
615*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800616class XMLText : public XMLNode
617{
Lee Thomason2c85a712012-01-31 08:24:24 -0800618 friend class XMLBase;
619 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800620public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800621 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800622
Lee Thomason751da522012-02-10 08:50:51 -0800623 virtual XMLText* ToText() { return this; }
624 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800625
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800626 /// Declare whether this should be CDATA or standard text.
Lee Thomason5ce89412012-03-20 13:23:44 -0700627 void SetCData( bool _isCData ) { this->isCData = _isCData; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800629 bool CData() const { return isCData; }
630
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800631 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800632 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
633 virtual bool ShallowEqual( const XMLNode* compare ) const;
634
Lee Thomason5492a1c2012-01-23 15:32:10 -0800635
636protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800637 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
638 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800639 XMLText( const XMLText& ); // not supported
640 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800641
642private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800643 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800644};
645
646
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800647/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800648class XMLComment : public XMLNode
649{
Lee Thomason2c85a712012-01-31 08:24:24 -0800650 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800651public:
Lee Thomason751da522012-02-10 08:50:51 -0800652 virtual XMLComment* ToComment() { return this; }
653 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800654
Lee Thomason56bdd022012-02-09 18:16:58 -0800655 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800657 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800658 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
659 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800660
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800662 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800663 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800664 XMLComment( const XMLComment& ); // not supported
665 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800666
Lee Thomason3f57d272012-01-11 15:30:03 -0800667private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800668};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800669
670
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800671/** In correct XML the declaration is the first entry in the file.
672 @verbatim
673 <?xml version="1.0" standalone="yes"?>
674 @endverbatim
675
676 TinyXML2 will happily read or write files without a declaration,
677 however.
678
679 The text of the declaration isn't interpreted. It is parsed
680 and written as a string.
681*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800682class XMLDeclaration : public XMLNode
683{
684 friend class XMLDocument;
685public:
686 virtual XMLDeclaration* ToDeclaration() { return this; }
687 virtual const XMLDeclaration* ToDeclaration() const { return this; }
688
689 virtual bool Accept( XMLVisitor* visitor ) const;
690
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800691 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800692 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
693 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800694
695protected:
696 XMLDeclaration( XMLDocument* doc );
697 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800698 XMLDeclaration( const XMLDeclaration& ); // not supported
699 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800700};
701
702
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800703/** Any tag that tinyXml doesn't recognize is saved as an
704 unknown. It is a tag of text, but should not be modified.
705 It will be written back to the XML, unchanged, when the file
706 is saved.
707
708 DTD tags get thrown into TiXmlUnknowns.
709*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800710class XMLUnknown : public XMLNode
711{
712 friend class XMLDocument;
713public:
714 virtual XMLUnknown* ToUnknown() { return this; }
715 virtual const XMLUnknown* ToUnknown() const { return this; }
716
717 virtual bool Accept( XMLVisitor* visitor ) const;
718
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800719 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800720 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
721 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800722
723protected:
724 XMLUnknown( XMLDocument* doc );
725 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800726 XMLUnknown( const XMLUnknown& ); // not supported
727 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800728};
729
730
Lee Thomason1ff38e02012-02-14 18:18:16 -0800731enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800732 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800733 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800734
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700735 XML_NO_ATTRIBUTE,
736 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800737
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700738 XML_ERROR_FILE_NOT_FOUND,
739 XML_ERROR_ELEMENT_MISMATCH,
740 XML_ERROR_PARSING_ELEMENT,
741 XML_ERROR_PARSING_ATTRIBUTE,
742 XML_ERROR_IDENTIFYING_TAG,
743 XML_ERROR_PARSING_TEXT,
744 XML_ERROR_PARSING_CDATA,
745 XML_ERROR_PARSING_COMMENT,
746 XML_ERROR_PARSING_DECLARATION,
747 XML_ERROR_PARSING_UNKNOWN,
748 XML_ERROR_EMPTY_DOCUMENT,
749 XML_ERROR_MISMATCHED_ELEMENT,
750 XML_ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751};
752
753
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800754/** An attribute is a name-value pair. Elements have an arbitrary
755 number of attributes, each with a unique name.
756
757 @note The attributes are not XMLNodes. You may only query the
758 Next() attribute in a list.
759*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800760class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800761{
762 friend class XMLElement;
763public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800764 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
765 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
766 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800767
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800768 /** IntAttribute interprets the attribute as an integer, and returns the value.
769 If the value isn't an integer, 0 will be returned. There is no error checking;
770 use QueryIntAttribute() if you need error checking.
771 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800773 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800774 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800775 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800776 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800777 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800778 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800779 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800780 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800781
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800782 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
783 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700784 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800785 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800786 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800787 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800788 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800789 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800790 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800791 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800795
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800796 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800797 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800798 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800799 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800800 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800801 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800802 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800803 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800804 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800805 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800806 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800807 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800808
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800809private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800810 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800811
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800812 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800813 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800814 XMLAttribute( const XMLAttribute& ); // not supported
815 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800816 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800817
Lee Thomason6f381b72012-03-02 12:59:39 -0800818 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800819
Lee Thomason751da522012-02-10 08:50:51 -0800820 mutable StrPair name;
821 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800822 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800823 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824};
825
826
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800827/** The element is a container class. It has a value, the element name,
828 and can contain other elements, text, comments, and unknowns.
829 Elements also contain an arbitrary number of attributes.
830*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800831class XMLElement : public XMLNode
832{
Lee Thomason2c85a712012-01-31 08:24:24 -0800833 friend class XMLBase;
834 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800835public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800836 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800837 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800838 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800839 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800840
Lee Thomason751da522012-02-10 08:50:51 -0800841 virtual XMLElement* ToElement() { return this; }
842 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800843 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800844
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800845 /** Given an attribute name, Attribute() returns the value
846 for the attribute of that name, or null if none exists.
847 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800848 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 -0800849
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800850 /** Given an attribute name, IntAttribute() returns the value
851 of the attribute interpreted as an integer. 0 will be
852 returned if there is an error. For a method with error
853 checking, see QueryIntAttribute()
854 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800855 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800856 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800857 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800858 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800859 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800860 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800861 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800862 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800863 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
864
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800865 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700866 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
867 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800868 doesn't exist. If successful, the result of the conversion
869 will be written to 'value'. If not successful, nothing will
870 be written to 'value'. This allows you to provide default
871 value:
872
873 @verbatim
874 int value = 10;
875 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
876 @endverbatim
877 */
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700878 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 -0800879 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700880 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 -0800881 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700882 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 -0800883 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700884 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 -0800885 /// See QueryIntAttribute()
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700886 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 -0800887
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, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800890 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800891 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800893 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800894 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800895 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800896 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800897 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800898
U-Stream\Leeae25a442012-02-17 17:48:16 -0800899 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800900 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800901 */
902 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800903
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800904 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800905 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800906 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800907 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800908
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800909 /** Convenience function for easy access to the text inside an element. Although easy
910 and concise, GetText() is limited compared to getting the TiXmlText child
911 and accessing it directly.
912
913 If the first child of 'this' is a TiXmlText, the GetText()
914 returns the character string of the Text node, else null is returned.
915
916 This is a convenient method for getting the text of simple contained text:
917 @verbatim
918 <foo>This is text</foo>
919 const char* str = fooElement->GetText();
920 @endverbatim
921
922 'str' will be a pointer to "This is text".
923
924 Note that this function can be misleading. If the element foo was created from
925 this XML:
926 @verbatim
927 <foo><b>This is text</b></foo>
928 @endverbatim
929
930 then the value of str would be null. The first child node isn't a text node, it is
931 another element. From this XML:
932 @verbatim
933 <foo>This is <b>text</b></foo>
934 @endverbatim
935 GetText() will return "This is ".
936 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800937 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800938
Lee Thomason2c85a712012-01-31 08:24:24 -0800939 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800940 enum {
941 OPEN, // <foo>
942 CLOSED, // <foo/>
943 CLOSING // </foo>
944 };
945 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800946 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
948 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800949
Lee Thomason50adb4c2012-02-13 15:07:09 -0800950private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800951 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800952 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800953 XMLElement( const XMLElement& ); // not supported
954 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800955
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800956 XMLAttribute* FindAttribute( const char* name );
957 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800958 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800959 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800960
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800961 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800962 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800963};
964
965
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800966/** A document binds together all the functionality.
967 It can be saved, loaded, and printed to the screen.
968 All Nodes are connected and allocated to a Document.
969 If the Document is deleted, all its Nodes are also deleted.
970*/
Lee Thomason67d61312012-01-24 16:01:51 -0800971class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800972{
Lee Thomasond1983222012-02-06 08:41:24 -0800973 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800974public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800975 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -0800976 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -0800977 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800978
Lee Thomason751da522012-02-10 08:50:51 -0800979 virtual XMLDocument* ToDocument() { return this; }
980 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800981
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800982 /**
983 Parse an XML file from a character string.
984 Returns XML_NO_ERROR (0) on success, or
985 an errorID.
986 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800987 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800988 /**
989 Load an XML file from disk.
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( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800994 /**
995 Load an XML file from disk. You are responsible
996 for providing and closing the FILE*.
997
998 Returns XML_NO_ERROR (0) on success, or
999 an errorID.
1000 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001001 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001002 /**
1003 Save the XML file to disk.
1004 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001005 void SaveFile( const char* filename );
1006
Lee Thomason6f381b72012-03-02 12:59:39 -08001007 bool ProcessEntities() const { return processEntities; }
1008
1009 /**
1010 Returns true if this document has a leading Byte Order Mark of UTF8.
1011 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001012 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001013
1014 /** Return the root element of DOM. Equivalent to FirstChildElement().
1015 To get the first node, use FirstChild().
1016 */
Lee Thomasond6277762012-02-22 16:00:12 -08001017 XMLElement* RootElement() { return FirstChildElement(); }
1018 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001019
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001020 /** Print the Document. If the Printer is not provided, it will
1021 print to stdout. If you provide Printer, this can print to a file:
1022 @verbatim
1023 XMLPrinter printer( fp );
1024 doc.Print( &printer );
1025 @endverbatim
1026
1027 Or you can use a printer to print to memory:
1028 @verbatim
1029 XMLPrinter printer;
1030 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001031 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001032 @endverbatim
1033 */
1034 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001035 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001036
Lee Thomason1ff38e02012-02-14 18:18:16 -08001037 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001038 Create a new Element associated with
1039 this Document. The memory for the Element
1040 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001041 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001042 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001043 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001044 Create a new Comment associated with
1045 this Document. The memory for the Comment
1046 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001047 */
1048 XMLComment* NewComment( const char* comment );
1049 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001050 Create a new Text associated with
1051 this Document. The memory for the Text
1052 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001053 */
1054 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055 /**
1056 Create a new Declaration associated with
1057 this Document. The memory for the object
1058 is managed by the Document.
1059 */
1060 XMLDeclaration* NewDeclaration( const char* text );
1061 /**
1062 Create a new Unknown associated with
1063 this Document. The memory for the object
1064 is managed by the Document.
1065 */
1066 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001067
U-Stream\Leeae25a442012-02-17 17:48:16 -08001068 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001069 Delete a node associated with this documented.
1070 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001071 */
1072 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1073
Lee Thomason67d61312012-01-24 16:01:51 -08001074 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001075
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001076 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001077 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001078 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001079 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001080 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001081 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001082 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001083 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001084 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001085 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001086
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001087 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001088 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001089
Lee Thomason6f381b72012-03-02 12:59:39 -08001090 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1091 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092
Lee Thomason3f57d272012-01-11 15:30:03 -08001093private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001094 XMLDocument( const XMLDocument& ); // not supported
1095 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001096 void InitDocument();
1097
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001098 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001099 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001100 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001101 const char* errorStr1;
1102 const char* errorStr2;
1103 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001104
1105 MemPoolT< sizeof(XMLElement) > elementPool;
1106 MemPoolT< sizeof(XMLAttribute) > attributePool;
1107 MemPoolT< sizeof(XMLText) > textPool;
1108 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001109};
1110
Lee Thomason7c913cd2012-01-26 18:32:34 -08001111
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001112
1113/**
1114 Printing functionality. The XMLPrinter gives you more
1115 options than the XMLDocument::Print() method.
1116
1117 It can:
1118 -# Print to memory.
1119 -# Print to a file you provide
1120 -# Print XML without a XMLDocument.
1121
1122 Print to Memory
1123
1124 @verbatim
1125 XMLPrinter printer;
1126 doc->Print( &printer );
1127 SomeFunctior( printer.CStr() );
1128 @endverbatim
1129
1130 Print to a File
1131
1132 You provide the file pointer.
1133 @verbatim
1134 XMLPrinter printer( fp );
1135 doc.Print( &printer );
1136 @endverbatim
1137
1138 Print without a XMLDocument
1139
1140 When loading, an XML parser is very useful. However, sometimes
1141 when saving, it just gets in the way. The code is often set up
1142 for streaming, and constructing the DOM is just overhead.
1143
1144 The Printer supports the streaming case. The following code
1145 prints out a trivially simple XML file without ever creating
1146 an XML document.
1147
1148 @verbatim
1149 XMLPrinter printer( fp );
1150 printer.OpenElement( "foo" );
1151 printer.PushAttribute( "foo", "bar" );
1152 printer.CloseElement();
1153 @endverbatim
1154*/
1155class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001156{
1157public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001158 /** Construct the printer. If the FILE* is specified,
1159 this will print to the FILE. Else it will print
1160 to memory, and the result is available in CStr()
1161 */
1162 XMLPrinter( FILE* file=0 );
1163 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001164
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001165 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001166 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001167 /** If streaming, start writing an element.
1168 The element must be closed with CloseElement()
1169 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001170 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001171 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001172 void PushAttribute( const char* name, const char* value );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001173 void PushAttribute( const char* name, int value );
1174 void PushAttribute( const char* name, unsigned value );
1175 void PushAttribute( const char* name, bool value );
1176 void PushAttribute( const char* name, double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001177 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001178 void CloseElement();
1179
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001180 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001181 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001182 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001183 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001184
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001185 void PushDeclaration( const char* value );
1186 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001187
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001188 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001189 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1190
1191 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1192 virtual bool VisitExit( const XMLElement& element );
1193
1194 virtual bool Visit( const XMLText& text );
1195 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001196 virtual bool Visit( const XMLDeclaration& declaration );
1197 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001198
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001199 /**
1200 If in print to memory mode, return a pointer to
1201 the XML file in memory.
1202 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001203 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001204
Lee Thomason5cae8972012-01-24 18:03:07 -08001205private:
1206 void SealElement();
1207 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001208 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001209 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001210
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001211 bool elementJustOpened;
1212 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001213 FILE* fp;
1214 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001215 int textDepth;
Lee Thomason6f381b72012-03-02 12:59:39 -08001216 bool processEntities;
Lee Thomason56bdd022012-02-09 18:16:58 -08001217
Lee Thomason857b8682012-01-25 17:50:25 -08001218 enum {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001219 ENTITY_RANGE = 64,
1220 BUF_SIZE = 200
Lee Thomason857b8682012-01-25 17:50:25 -08001221 };
1222 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001223 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001224
Lee Thomason2c85a712012-01-31 08:24:24 -08001225 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001226 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001227};
1228
1229
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001230} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001231
U-Lama\Lee560bd472011-12-28 19:42:49 -08001232
1233
U-Stream\Leeae25a442012-02-17 17:48:16 -08001234#endif // TINYXML2_INCLUDED