blob: b5a908ebe0bf6285a3fb48b899330212c67cf737 [file] [log] [blame]
Lee Thomason50f97b22012-02-11 16:33:40 -08001#ifndef TINYXML_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002#define TINYXML2_INCLUDED
3
Lee Thomason2c85a712012-01-31 08:24:24 -08004
U-Lama\Lee4cee6112011-12-31 14:58:18 -08005#include <limits.h>
Lee Thomasonce0763e2012-01-11 15:43:54 -08006#include <ctype.h>
7#include <stdio.h>
Lee Thomason2c85a712012-01-31 08:24:24 -08008#include <memory.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -08009
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080010/* TODO: create main page description.
11 TODO: add 'lastAttribute' for faster parsing.
12*/
13
U-Lama\Lee4cee6112011-12-31 14:58:18 -080014#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
15 #ifndef DEBUG
16 #define DEBUG
17 #endif
18#endif
19
20
21#if defined(DEBUG)
22 #if defined(_MSC_VER)
23 #define TIXMLASSERT( x ) if ( !(x)) { _asm { int 3 } } //if ( !(x)) WinDebugBreak()
24 #elif defined (ANDROID_NDK)
25 #include <android/log.h>
26 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
27 #else
28 #include <assert.h>
29 #define TIXMLASSERT assert
30 #endif
31#else
32 #define TIXMLASSERT( x ) {}
33#endif
34
U-Lama\Leee13c3e62011-12-28 14:36:55 -080035
Lee Thomason1a1d4a72012-02-15 09:09:25 -080036// Deprecated library function hell. Compilers want to use the
37// new safe versions. This probably doesn't fully address the problem,
38// but it gets closer. There are too many compilers for me to fully
39// test. If you get compilation troubles, undefine TIXML_SAFE
40
41#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
42 // Microsoft visual studio, version 2005 and higher.
43 #define TIXML_SNPRINTF _snprintf_s
44 #define TIXML_SSCANF sscanf_s
45#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
46 // Microsoft visual studio, version 6 and higher.
47 //#pragma message( "Using _sn* functions." )
48 #define TIXML_SNPRINTF _snprintf
49 #define TIXML_SSCANF sscanf
50#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080051 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080052 //#warning( "Using sn* functions." )
53 #define TIXML_SNPRINTF snprintf
54 #define TIXML_SSCANF sscanf
55#else
56 #define TIXML_SNPRINTF snprintf
57 #define TIXML_SSCANF sscanf
58#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080059
60
U-Lama\Leee13c3e62011-12-28 14:36:55 -080061namespace tinyxml2
62{
Lee Thomasonce0763e2012-01-11 15:43:54 -080063class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -080064class XMLElement;
65class XMLAttribute;
66class XMLComment;
67class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -080068class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -080069class XMLDeclaration;
70class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -080071
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080072class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -080073
U-Stream\Leeae25a442012-02-17 17:48:16 -080074/*
75 A class that wraps strings. Normally stores the start and end
76 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080077 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -080078 manage) a traditional char[]
79*/
Lee Thomason39ede242012-01-20 11:27:56 -080080class StrPair
81{
Lee Thomasond34f52c2012-01-20 12:55:24 -080082public:
Lee Thomason39ede242012-01-20 11:27:56 -080083 enum {
Lee Thomasone4422302012-01-20 17:59:50 -080084 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -080085 NEEDS_NEWLINE_NORMALIZATION = 0x02,
86
87 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
88 ATTRIBUTE_NAME = 0,
89 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
90 COMMENT = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason39ede242012-01-20 11:27:56 -080091 };
92
93 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -080094 ~StrPair();
95
Lee Thomasone4422302012-01-20 17:59:50 -080096 void Set( char* start, char* end, int flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097 Reset();
Lee Thomason39ede242012-01-20 11:27:56 -080098 this->start = start; this->end = end; this->flags = flags | NEEDS_FLUSH;
99 }
100 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800101 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800102
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800103 void SetInternedStr( const char* str ) { Reset(); this->start = (char*) str; }
104 void SetStr( const char* str, int flags=0 );
105
Lee Thomason56bdd022012-02-09 18:16:58 -0800106 char* ParseText( char* in, const char* endTag, int strFlags );
107 char* ParseName( char* in );
108
Lee Thomason2c85a712012-01-31 08:24:24 -0800109
Lee Thomason39ede242012-01-20 11:27:56 -0800110private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800111 void Reset();
112
Lee Thomasone4422302012-01-20 17:59:50 -0800113 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114 NEEDS_FLUSH = 0x100,
115 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800116 };
117
Lee Thomason39ede242012-01-20 11:27:56 -0800118 // After parsing, if *end != 0, it can be set to zero.
119 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800120 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800121 char* end;
122};
123
U-Lama\Lee560bd472011-12-28 19:42:49 -0800124
U-Stream\Leeae25a442012-02-17 17:48:16 -0800125/*
126 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
127 Has a small initial memory pool, so that low or no usage will not
128 cause a call to new/delete
129*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800130template <class T, int INIT>
131class DynArray
132{
133public:
134 DynArray< T, INIT >()
135 {
136 mem = pool;
137 allocated = INIT;
138 size = 0;
139 }
140 ~DynArray()
141 {
142 if ( mem != pool ) {
143 delete mem;
144 }
145 }
146 void Push( T t )
147 {
148 EnsureCapacity( size+1 );
149 mem[size++] = t;
150 }
151
152 T* PushArr( int count )
153 {
154 EnsureCapacity( size+count );
155 T* ret = &mem[size];
156 size += count;
157 return ret;
158 }
159 T Pop() {
160 return mem[--size];
161 }
162 void PopArr( int count )
163 {
164 TIXMLASSERT( size >= count );
165 size -= count;
166 }
167
U-Stream\Leeae25a442012-02-17 17:48:16 -0800168 bool Empty() const { return size == 0; }
169 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
170 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
171 int Size() const { return size; }
172 int Capacity() const { return allocated; }
173 const T* Mem() const { return mem; }
174 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800175
176
177private:
178 void EnsureCapacity( int cap ) {
179 if ( cap > allocated ) {
180 int newAllocated = cap * 2;
181 T* newMem = new T[newAllocated];
182 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
183 if ( mem != pool ) delete [] mem;
184 mem = newMem;
185 allocated = newAllocated;
186 }
187 }
188
189 T* mem;
190 T pool[INIT];
191 int allocated; // objects allocated
192 int size; // number objects in use
193};
194
Lee Thomason50adb4c2012-02-13 15:07:09 -0800195
U-Stream\Leeae25a442012-02-17 17:48:16 -0800196/*
197 Parent virtual class a a pool for fast allocation
198 and deallocation of objects.
199*/
Lee Thomasond1983222012-02-06 08:41:24 -0800200class MemPool
201{
202public:
203 MemPool() {}
204 virtual ~MemPool() {}
205
206 virtual int ItemSize() const = 0;
207 virtual void* Alloc() = 0;
208 virtual void Free( void* ) = 0;
209};
210
Lee Thomason50adb4c2012-02-13 15:07:09 -0800211
U-Stream\Leeae25a442012-02-17 17:48:16 -0800212/*
213 Template child class to create pools of the correct type.
214*/
Lee Thomasond1983222012-02-06 08:41:24 -0800215template< int SIZE >
216class MemPoolT : public MemPool
217{
218public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800219 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800220 ~MemPoolT() {
221 // Delete the blocks.
222 for( int i=0; i<blockPtrs.Size(); ++i ) {
223 delete blockPtrs[i];
224 }
225 }
226
227 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800228 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800229
230 virtual void* Alloc() {
231 if ( !root ) {
232 // Need a new block.
233 Block* block = new Block();
234 blockPtrs.Push( block );
235
236 for( int i=0; i<COUNT-1; ++i ) {
237 block->chunk[i].next = &block->chunk[i+1];
238 }
239 block->chunk[COUNT-1].next = 0;
240 root = block->chunk;
241 }
242 void* result = root;
243 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800244
245 ++currentAllocs;
246 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
247 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800248 return result;
249 }
250 virtual void Free( void* mem ) {
251 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800252 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800253 Chunk* chunk = (Chunk*)mem;
254 memset( chunk, 0xfe, sizeof(Chunk) );
255 chunk->next = root;
256 root = chunk;
257 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800258 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800259 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
260 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800261 }
Lee Thomasond1983222012-02-06 08:41:24 -0800262
263private:
264 enum { COUNT = 1024/SIZE };
265 union Chunk {
266 Chunk* next;
267 char mem[SIZE];
268 };
269 struct Block {
270 Chunk chunk[COUNT];
271 };
272 DynArray< Block*, 10 > blockPtrs;
273 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800274
275 int currentAllocs;
276 int nAllocs;
277 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800278};
279
Lee Thomason2c85a712012-01-31 08:24:24 -0800280
Lee Thomason56bdd022012-02-09 18:16:58 -0800281
282/**
283 Implements the interface to the "Visitor pattern" (see the Accept() method.)
284 If you call the Accept() method, it requires being passed a XMLVisitor
285 class to handle callbacks. For nodes that contain other nodes (Document, Element)
286 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
287 are simply called with Visit().
288
289 If you return 'true' from a Visit method, recursive parsing will continue. If you return
290 false, <b>no children of this node or its sibilings</b> will be Visited.
291
292 All flavors of Visit methods have a default implementation that returns 'true' (continue
293 visiting). You need to only override methods that are interesting to you.
294
295 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
296
297 You should never change the document from a callback.
298
299 @sa XMLNode::Accept()
300*/
301class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800302{
303public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800304 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800305
Lee Thomason56bdd022012-02-09 18:16:58 -0800306 /// Visit a document.
307 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
308 /// Visit a document.
309 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
310
311 /// Visit an element.
312 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
313 /// Visit an element.
314 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
315
316 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800317 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800318 /// Visit a text node
319 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
320 /// Visit a comment node
321 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
322 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800323 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800324};
325
326
U-Stream\Leeae25a442012-02-17 17:48:16 -0800327/*
328 Utility functionality.
329*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800330class XMLUtil
331{
Lee Thomasond1983222012-02-06 08:41:24 -0800332public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800333 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
334 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800335 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
336 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800337
338 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
339 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800340 if ( p == q ) {
341 return true;
342 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800343 while( *p && *q && *p == *q && n<nChar ) {
344 ++p; ++q; ++n;
345 }
346 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
347 return true;
348 }
349 return false;
350 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800351 inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800352 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
353 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800354
355 static const char* ReadBOM( const char* p, bool* hasBOM );
356 // p is the starting location,
357 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800358 static const char* GetCharacterRef( const char* p, char* value, int* length );
359 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800360};
361
Lee Thomason5cae8972012-01-24 18:03:07 -0800362
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800363/** XMLNode is a base class for every object that is in the
364 XML Document Object Model (DOM), except XMLAttributes.
365 Nodes have siblings, a parent, and children which can
366 be navigated. A node is always in a XMLDocument.
367 The type of a TiXmlNode can be queried, and it can
368 be cast to its more defined type.
369
370 An XMLDocument allocates memory for all its Nodes.
371 When the XMLDocument gets deleted, all its Nodes
372 will also be deleted.
373
374 @verbatim
375 A Document can contain: Element (container or leaf)
376 Comment (leaf)
377 Unknown (leaf)
378 Declaration( leaf )
379
380 An Element can contain: Element (container or leaf)
381 Text (leaf)
382 Attributes (not on tree)
383 Comment (leaf)
384 Unknown (leaf)
385
386 @endverbatim
387*/
Lee Thomasond1983222012-02-06 08:41:24 -0800388class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800389{
390 friend class XMLDocument;
391 friend class XMLElement;
392public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800393
394 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800395 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800396 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800397 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800398
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800399 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
400 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
401 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
402 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
403 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
404 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800405
Lee Thomason50f97b22012-02-11 16:33:40 -0800406 virtual const XMLElement* ToElement() const { return 0; }
407 virtual const XMLText* ToText() const { return 0; }
408 virtual const XMLComment* ToComment() const { return 0; }
409 virtual const XMLDocument* ToDocument() const { return 0; }
410 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
411 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800412
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800413 /** The meaning of 'value' changes for the specific type.
414 @verbatim
415 Document: empy
416 Element: name of the element
417 Comment: the comment text
418 Unknown: the tag contents
419 Text: the text string
420 @endverbatim
421 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800422 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800423 /** Set the Value of an XML node.
424 @sa Value()
425 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800426 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800427
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800428 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800429 const XMLNode* Parent() const { return parent; }
430 XMLNode* Parent() { return parent; }
431
Lee Thomason50f97b22012-02-11 16:33:40 -0800432 /// Returns true if this node has no children.
433 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800434
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800435 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800436 const XMLNode* FirstChild() const { return firstChild; }
437 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800438 /** Get the first child element, or optionally the first child
439 element with the specified name.
440 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800441 const XMLElement* FirstChildElement( const char* value=0 ) const;
442 XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800443
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800444 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800445 const XMLNode* LastChild() const { return lastChild; }
446 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800447
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800448 /** Get the last child element or optionally the last child
449 element with the specified name.
450 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800451 const XMLElement* LastChildElement( const char* value=0 ) const;
452 XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); }
453
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800454 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800455 const XMLNode* PreviousSibling() const { return prev; }
456 XMLNode* PreviousSibling() { return prev; }
457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800458 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800459 const XMLNode* PreviousSiblingElement( const char* value=0 ) const ;
460 XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
461
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800462 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800463 const XMLNode* NextSibling() const { return next; }
464 XMLNode* NextSibling() { return next; }
465
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800466 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800467 const XMLNode* NextSiblingElement( const char* value=0 ) const;
468 XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
469
Lee Thomason1ff38e02012-02-14 18:18:16 -0800470 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800471 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800472 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800473 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800474 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800475 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800476 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800477 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800478 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800479 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800480 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800481 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
482
U-Stream\Leeae25a442012-02-17 17:48:16 -0800483 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800484 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800485 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800486 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800487
488 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800489 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800490 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800491 void DeleteChild( XMLNode* node );
492
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800493 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
494 XML tree will be conditionally visited and the host will be called back
495 via the TiXmlVisitor interface.
496
497 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
498 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
499 interface versus any other.)
500
501 The interface has been based on ideas from:
502
503 - http://www.saxproject.org/
504 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
505
506 Which are both good references for "visiting".
507
508 An example of using Accept():
509 @verbatim
510 TiXmlPrinter printer;
511 tinyxmlDoc.Accept( &printer );
512 const char* xmlcstr = printer.CStr();
513 @endverbatim
514 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800515 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800516
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800517 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800518 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800519
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800520protected:
521 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800522 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800523 XMLNode( const XMLNode& ); // not supported
524 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800525
Lee Thomason3f57d272012-01-11 15:30:03 -0800526 XMLDocument* document;
527 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800528 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800529
530 XMLNode* firstChild;
531 XMLNode* lastChild;
532
533 XMLNode* prev;
534 XMLNode* next;
535
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800536private:
Lee Thomasond1983222012-02-06 08:41:24 -0800537 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800538 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800539};
540
541
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800542/** XML text.
543
544 Note that a text node can have child element nodes, for example:
545 @verbatim
546 <root>This is <b>bold</b></root>
547 @endverbatim
548
549 A text node can have 2 ways to output the next. "normal" output
550 and CDATA. It will default to the mode it was parsed from the XML file and
551 you generally want to leave it alone, but you can change the output mode with
552 SetCDATA() and query it with CDATA().
553*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800554class XMLText : public XMLNode
555{
Lee Thomason2c85a712012-01-31 08:24:24 -0800556 friend class XMLBase;
557 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800558public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800559 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800560
Lee Thomason751da522012-02-10 08:50:51 -0800561 virtual XMLText* ToText() { return this; }
562 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800563
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800564 /// Declare whether this should be CDATA or standard text.
565 void SetCData( bool isCData ) { this->isCData = isCData; }
566 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800567 bool CData() const { return isCData; }
568
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800569 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800570
571protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800572 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
573 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800574 XMLText( const XMLText& ); // not supported
575 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800576
577private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800578 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800579};
580
581
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800582/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800583class XMLComment : public XMLNode
584{
Lee Thomason2c85a712012-01-31 08:24:24 -0800585 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800586public:
Lee Thomason751da522012-02-10 08:50:51 -0800587 virtual XMLComment* ToComment() { return this; }
588 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800589
Lee Thomason56bdd022012-02-09 18:16:58 -0800590 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800591
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800592 char* ParseDeep( char*, StrPair* endTag );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800593
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800594protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800595 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800596 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800597 XMLComment( const XMLComment& ); // not supported
598 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800599
Lee Thomason3f57d272012-01-11 15:30:03 -0800600private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800601};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800602
603
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800604/** In correct XML the declaration is the first entry in the file.
605 @verbatim
606 <?xml version="1.0" standalone="yes"?>
607 @endverbatim
608
609 TinyXML2 will happily read or write files without a declaration,
610 however.
611
612 The text of the declaration isn't interpreted. It is parsed
613 and written as a string.
614*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800615class XMLDeclaration : public XMLNode
616{
617 friend class XMLDocument;
618public:
619 virtual XMLDeclaration* ToDeclaration() { return this; }
620 virtual const XMLDeclaration* ToDeclaration() const { return this; }
621
622 virtual bool Accept( XMLVisitor* visitor ) const;
623
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800624 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800625
626protected:
627 XMLDeclaration( XMLDocument* doc );
628 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800629 XMLDeclaration( const XMLDeclaration& ); // not supported
630 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800631};
632
633
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800634/** Any tag that tinyXml doesn't recognize is saved as an
635 unknown. It is a tag of text, but should not be modified.
636 It will be written back to the XML, unchanged, when the file
637 is saved.
638
639 DTD tags get thrown into TiXmlUnknowns.
640*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800641class XMLUnknown : public XMLNode
642{
643 friend class XMLDocument;
644public:
645 virtual XMLUnknown* ToUnknown() { return this; }
646 virtual const XMLUnknown* ToUnknown() const { return this; }
647
648 virtual bool Accept( XMLVisitor* visitor ) const;
649
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800650 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason50f97b22012-02-11 16:33:40 -0800651
652protected:
653 XMLUnknown( XMLDocument* doc );
654 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800655 XMLUnknown( const XMLUnknown& ); // not supported
656 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800657};
658
659
Lee Thomason1ff38e02012-02-14 18:18:16 -0800660enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800661 XML_NO_ERROR = 0,
662
Lee Thomason1ff38e02012-02-14 18:18:16 -0800663 NO_ATTRIBUTE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800664 WRONG_ATTRIBUTE_TYPE,
665
666 ERROR_FILE_NOT_FOUND,
667 ERROR_ELEMENT_MISMATCH,
668 ERROR_PARSING_ELEMENT,
669 ERROR_PARSING_ATTRIBUTE,
670 ERROR_IDENTIFYING_TAG,
671 ERROR_PARSING_TEXT,
672 ERROR_PARSING_CDATA,
673 ERROR_PARSING_COMMENT,
674 ERROR_PARSING_DECLARATION,
Lee Thomasond6277762012-02-22 16:00:12 -0800675 ERROR_PARSING_UNKNOWN,
676 ERROR_EMPTY_DOCUMENT,
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800677 ERROR_MISMATCHED_ELEMENT,
678 ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800679};
680
681
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800682/** An attribute is a name-value pair. Elements have an arbitrary
683 number of attributes, each with a unique name.
684
685 @note The attributes are not XMLNodes. You may only query the
686 Next() attribute in a list.
687*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800688class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689{
690 friend class XMLElement;
691public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800692 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
693 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
694 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800696 /** IntAttribute interprets the attribute as an integer, and returns the value.
697 If the value isn't an integer, 0 will be returned. There is no error checking;
698 use QueryIntAttribute() if you need error checking.
699 */
U-Stream\Leeae25a442012-02-17 17:48:16 -0800700 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800701 /// Query as an unsigned integer. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800702 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800703 /// Query as a boolean. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800704 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800705 /// Query as a double. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800706 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800707 /// Query as a float. See IntAttribute()
U-Stream\Leeae25a442012-02-17 17:48:16 -0800708 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( &f ); return f; }
709
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800710 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
711 in the provided paremeter. The function will return XML_NO_ERROR on success,
712 and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
713 */
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714 int QueryIntAttribute( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800715 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800716 int QueryUnsignedAttribute( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800717 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718 int QueryBoolAttribute( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800719 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720 int QueryDoubleAttribute( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800721 /// See QueryIntAttribute
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722 int QueryFloatAttribute( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800723
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800724 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800726 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800727 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800728 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800730 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800731 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800732 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800733 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800734 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800735 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800736
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800737private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800738 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800739
Lee Thomasond1983222012-02-06 08:41:24 -0800740 XMLAttribute( XMLElement* element ) : next( 0 ) {}
741 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800742 XMLAttribute( const XMLAttribute& ); // not supported
743 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800744 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800745
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746 char* ParseDeep( char* p );
747
Lee Thomason751da522012-02-10 08:50:51 -0800748 mutable StrPair name;
749 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800751 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800752};
753
754
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800755/** The element is a container class. It has a value, the element name,
756 and can contain other elements, text, comments, and unknowns.
757 Elements also contain an arbitrary number of attributes.
758*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800759class XMLElement : public XMLNode
760{
Lee Thomason2c85a712012-01-31 08:24:24 -0800761 friend class XMLBase;
762 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800763public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800764 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800765 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800766 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800767 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800768
Lee Thomason751da522012-02-10 08:50:51 -0800769 virtual XMLElement* ToElement() { return this; }
770 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800771 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800772
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800773 /** Given an attribute name, Attribute() returns the value
774 for the attribute of that name, or null if none exists.
775 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800776 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 -0800777
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800778 /** Given an attribute name, IntAttribute() returns the value
779 of the attribute interpreted as an integer. 0 will be
780 returned if there is an error. For a method with error
781 checking, see QueryIntAttribute()
782 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800783 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800784 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800785 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800786 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800787 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800789 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800790 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800791 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793 /** Given an attribute name, QueryIntAttribute() returns
794 XML_NO_ERROR, WRONG_ATTRIBUTE_TYPE if the conversion
795 can't be performed, or NO_ATTRIBUTE if the attribute
796 doesn't exist. If successful, the result of the conversion
797 will be written to 'value'. If not successful, nothing will
798 be written to 'value'. This allows you to provide default
799 value:
800
801 @verbatim
802 int value = 10;
803 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
804 @endverbatim
805 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800806 int QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800807 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800808 int QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800809 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800810 int QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800811 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800812 int QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800813 /// See QueryIntAttribute()
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800814 int QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800815
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800816 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800817 void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800818 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800819 void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800820 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800821 void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800822 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800823 void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800824 /// Sets the named attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800825 void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800826
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800828 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800829 */
830 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800831
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800832 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800833 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800834 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800835 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800836
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800837 /** Convenience function for easy access to the text inside an element. Although easy
838 and concise, GetText() is limited compared to getting the TiXmlText child
839 and accessing it directly.
840
841 If the first child of 'this' is a TiXmlText, the GetText()
842 returns the character string of the Text node, else null is returned.
843
844 This is a convenient method for getting the text of simple contained text:
845 @verbatim
846 <foo>This is text</foo>
847 const char* str = fooElement->GetText();
848 @endverbatim
849
850 'str' will be a pointer to "This is text".
851
852 Note that this function can be misleading. If the element foo was created from
853 this XML:
854 @verbatim
855 <foo><b>This is text</b></foo>
856 @endverbatim
857
858 then the value of str would be null. The first child node isn't a text node, it is
859 another element. From this XML:
860 @verbatim
861 <foo>This is <b>text</b></foo>
862 @endverbatim
863 GetText() will return "This is ".
864 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800865 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800866
Lee Thomason2c85a712012-01-31 08:24:24 -0800867 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800868 enum {
869 OPEN, // <foo>
870 CLOSED, // <foo/>
871 CLOSING // </foo>
872 };
873 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800874 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800875
Lee Thomason50adb4c2012-02-13 15:07:09 -0800876private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800877 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800878 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800879 XMLElement( const XMLElement& ); // not supported
880 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800881
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800882 XMLAttribute* FindAttribute( const char* name );
883 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800884 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800885 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800886
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800888 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800889};
890
891
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892/** A document binds together all the functionality.
893 It can be saved, loaded, and printed to the screen.
894 All Nodes are connected and allocated to a Document.
895 If the Document is deleted, all its Nodes are also deleted.
896*/
Lee Thomason67d61312012-01-24 16:01:51 -0800897class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800898{
Lee Thomasond1983222012-02-06 08:41:24 -0800899 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800900public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800901 /// constructor
Lee Thomason18d68bd2012-01-26 18:17:26 -0800902 XMLDocument();
Lee Thomason3f57d272012-01-11 15:30:03 -0800903 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800904
Lee Thomason751da522012-02-10 08:50:51 -0800905 virtual XMLDocument* ToDocument() { return this; }
906 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800907
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800908 /**
909 Parse an XML file from a character string.
910 Returns XML_NO_ERROR (0) on success, or
911 an errorID.
912 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800913 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800914 /**
915 Load an XML file from disk.
916 Returns XML_NO_ERROR (0) on success, or
917 an errorID.
918 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800919 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800920 /**
921 Load an XML file from disk. You are responsible
922 for providing and closing the FILE*.
923
924 Returns XML_NO_ERROR (0) on success, or
925 an errorID.
926 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800927 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800928 /**
929 Save the XML file to disk.
930 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800931 void SaveFile( const char* filename );
932
933 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800934
935 /** Return the root element of DOM. Equivalent to FirstChildElement().
936 To get the first node, use FirstChild().
937 */
Lee Thomasond6277762012-02-22 16:00:12 -0800938 XMLElement* RootElement() { return FirstChildElement(); }
939 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800940
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800941 /** Print the Document. If the Printer is not provided, it will
942 print to stdout. If you provide Printer, this can print to a file:
943 @verbatim
944 XMLPrinter printer( fp );
945 doc.Print( &printer );
946 @endverbatim
947
948 Or you can use a printer to print to memory:
949 @verbatim
950 XMLPrinter printer;
951 doc->Print( &printer );
952 SomeFunctior( printer.CStr() );
953 @endverbatim
954 */
955 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -0800956 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800957
Lee Thomason1ff38e02012-02-14 18:18:16 -0800958 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800959 Create a new Element associated with
960 this Document. The memory for the Element
961 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800962 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800963 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800964 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800965 Create a new Comment associated with
966 this Document. The memory for the Comment
967 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800968 */
969 XMLComment* NewComment( const char* comment );
970 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800971 Create a new Text associated with
972 this Document. The memory for the Text
973 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800974 */
975 XMLText* NewText( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -0800976
U-Stream\Leeae25a442012-02-17 17:48:16 -0800977 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800978 Delete a node associated with this documented.
979 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800980 */
981 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
982
Lee Thomason67d61312012-01-24 16:01:51 -0800983 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -0800984
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800985 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800986 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800987 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800988 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800989 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -0800990 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800991 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -0800992 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800993 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800994 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800995
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800996 // internal
Lee Thomasond1983222012-02-06 08:41:24 -0800997 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -0800998
Lee Thomason3f57d272012-01-11 15:30:03 -0800999private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001000 XMLDocument( const XMLDocument& ); // not supported
1001 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001002 void InitDocument();
1003
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001004 bool writeBOM;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001005 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001006 const char* errorStr1;
1007 const char* errorStr2;
1008 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001009
1010 MemPoolT< sizeof(XMLElement) > elementPool;
1011 MemPoolT< sizeof(XMLAttribute) > attributePool;
1012 MemPoolT< sizeof(XMLText) > textPool;
1013 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001014};
1015
Lee Thomason7c913cd2012-01-26 18:32:34 -08001016
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001017
1018/**
1019 Printing functionality. The XMLPrinter gives you more
1020 options than the XMLDocument::Print() method.
1021
1022 It can:
1023 -# Print to memory.
1024 -# Print to a file you provide
1025 -# Print XML without a XMLDocument.
1026
1027 Print to Memory
1028
1029 @verbatim
1030 XMLPrinter printer;
1031 doc->Print( &printer );
1032 SomeFunctior( printer.CStr() );
1033 @endverbatim
1034
1035 Print to a File
1036
1037 You provide the file pointer.
1038 @verbatim
1039 XMLPrinter printer( fp );
1040 doc.Print( &printer );
1041 @endverbatim
1042
1043 Print without a XMLDocument
1044
1045 When loading, an XML parser is very useful. However, sometimes
1046 when saving, it just gets in the way. The code is often set up
1047 for streaming, and constructing the DOM is just overhead.
1048
1049 The Printer supports the streaming case. The following code
1050 prints out a trivially simple XML file without ever creating
1051 an XML document.
1052
1053 @verbatim
1054 XMLPrinter printer( fp );
1055 printer.OpenElement( "foo" );
1056 printer.PushAttribute( "foo", "bar" );
1057 printer.CloseElement();
1058 @endverbatim
1059*/
1060class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001061{
1062public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001063 /** Construct the printer. If the FILE* is specified,
1064 this will print to the FILE. Else it will print
1065 to memory, and the result is available in CStr()
1066 */
1067 XMLPrinter( FILE* file=0 );
1068 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001069
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001070 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001071 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001072 /** If streaming, start writing an element.
1073 The element must be closed with CloseElement()
1074 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001075 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001076 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001077 void PushAttribute( const char* name, const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001078 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001079 void CloseElement();
1080
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001081 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001082 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001083 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001084 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001085
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001086 void PushDeclaration( const char* value );
1087 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001088
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001089 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001090 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1091
1092 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1093 virtual bool VisitExit( const XMLElement& element );
1094
1095 virtual bool Visit( const XMLText& text );
1096 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001097 virtual bool Visit( const XMLDeclaration& declaration );
1098 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001099
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001100 /**
1101 If in print to memory mode, return a pointer to
1102 the XML file in memory.
1103 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001104 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001105
Lee Thomason5cae8972012-01-24 18:03:07 -08001106private:
1107 void SealElement();
1108 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001109 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001110 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001111
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001112 bool elementJustOpened;
1113 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001114 FILE* fp;
1115 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001116 int textDepth;
1117
Lee Thomason857b8682012-01-25 17:50:25 -08001118 enum {
Lee Thomason951d8832012-01-26 08:47:06 -08001119 ENTITY_RANGE = 64
Lee Thomason857b8682012-01-25 17:50:25 -08001120 };
1121 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001122 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001123
Lee Thomason2c85a712012-01-31 08:24:24 -08001124 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001125 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001126};
1127
1128
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001129}; // tinyxml2
1130
U-Lama\Lee560bd472011-12-28 19:42:49 -08001131
1132
U-Stream\Leeae25a442012-02-17 17:48:16 -08001133#endif // TINYXML2_INCLUDED