blob: f9348ab5d75367462aa1585a67e8f67e19067e13 [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>
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070032 #include <cstdarg>
Lee Thomason5ce89412012-03-20 13:23:44 -070033#else
34 // Not completely sure all the interesting systems
35 // can handle the new headers; can switch this if
36 // there is an include problem.
37 #include <limits.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <memory.h> // Needed by mac.
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -070041#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080042
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070043
Lee Thomason7d00b9a2012-02-27 17:54:22 -080044/*
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080045 TODO: add 'lastAttribute' for faster parsing.
Lee Thomason7d00b9a2012-02-27 17:54:22 -080046 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080047*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080048/*
49 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
50*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080051
U-Lama\Lee4cee6112011-12-31 14:58:18 -080052#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
53 #ifndef DEBUG
54 #define DEBUG
55 #endif
56#endif
57
58
59#if defined(DEBUG)
60 #if defined(_MSC_VER)
Guillermo A. Amaral68b0c872012-03-24 11:07:19 -070061 #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
U-Lama\Lee4cee6112011-12-31 14:58:18 -080062 #elif defined (ANDROID_NDK)
63 #include <android/log.h>
64 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
65 #else
66 #include <assert.h>
67 #define TIXMLASSERT assert
68 #endif
69#else
70 #define TIXMLASSERT( x ) {}
71#endif
72
U-Lama\Leee13c3e62011-12-28 14:36:55 -080073
Lee Thomason1a1d4a72012-02-15 09:09:25 -080074#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
75 // Microsoft visual studio, version 2005 and higher.
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070076 /*int _snprintf_s(
77 char *buffer,
78 size_t sizeOfBuffer,
79 size_t count,
80 const char *format [,
81 argument] ...
82 );*/
83 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) {
84 va_list va;
85 va_start( va, format );
86 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
87 va_end( va );
88 return result;
89 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -080090 #define TIXML_SSCANF sscanf_s
Lee Thomason1a1d4a72012-02-15 09:09:25 -080091#elif defined(__GNUC__) && (__GNUC__ >= 3 )
U-Stream\Leeae25a442012-02-17 17:48:16 -080092 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080093 //#warning( "Using sn* functions." )
94 #define TIXML_SNPRINTF snprintf
95 #define TIXML_SSCANF sscanf
96#else
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070097 #define TIXML_SNPRINTF snprintf( buf, size, x ) snprintf( buf, size, x )
Lee Thomason1a1d4a72012-02-15 09:09:25 -080098 #define TIXML_SSCANF sscanf
99#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -0800100
Lee Thomason7f7b1622012-03-24 12:49:03 -0700101static const int TIXML2_MAJOR_VERSION = 0;
102static const int TIXML2_MINOR_VERSION = 9;
Lee Thomason (grinliz)c8678e22012-04-04 12:39:53 -0700103static const int TIXML2_PATCH_VERSION = 3;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800104
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800105namespace tinyxml2
106{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800107class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800108class XMLElement;
109class XMLAttribute;
110class XMLComment;
111class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800112class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800113class XMLDeclaration;
114class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800115
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800116class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800117
U-Stream\Leeae25a442012-02-17 17:48:16 -0800118/*
119 A class that wraps strings. Normally stores the start and end
120 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800121 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800122 manage) a traditional char[]
123*/
Lee Thomason39ede242012-01-20 11:27:56 -0800124class StrPair
125{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800126public:
Lee Thomason39ede242012-01-20 11:27:56 -0800127 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800128 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800129 NEEDS_NEWLINE_NORMALIZATION = 0x02,
130
131 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800132 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800133 ATTRIBUTE_NAME = 0,
134 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800135 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700136 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800137 };
138
139 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800140 ~StrPair();
141
Lee Thomason5ce89412012-03-20 13:23:44 -0700142 void Set( char* _start, char* _end, int _flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143 Reset();
Lee Thomason5ce89412012-03-20 13:23:44 -0700144 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800145 }
146 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800147 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800148
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700149 void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800150 void SetStr( const char* str, int flags=0 );
151
Lee Thomason56bdd022012-02-09 18:16:58 -0800152 char* ParseText( char* in, const char* endTag, int strFlags );
153 char* ParseName( char* in );
154
Lee Thomason2c85a712012-01-31 08:24:24 -0800155
Lee Thomason39ede242012-01-20 11:27:56 -0800156private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800157 void Reset();
158
Lee Thomasone4422302012-01-20 17:59:50 -0800159 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800160 NEEDS_FLUSH = 0x100,
161 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800162 };
163
Lee Thomason39ede242012-01-20 11:27:56 -0800164 // After parsing, if *end != 0, it can be set to zero.
165 int flags;
Lee Thomasone4422302012-01-20 17:59:50 -0800166 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800167 char* end;
168};
169
U-Lama\Lee560bd472011-12-28 19:42:49 -0800170
U-Stream\Leeae25a442012-02-17 17:48:16 -0800171/*
172 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
173 Has a small initial memory pool, so that low or no usage will not
174 cause a call to new/delete
175*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800176template <class T, int INIT>
177class DynArray
178{
179public:
180 DynArray< T, INIT >()
181 {
182 mem = pool;
183 allocated = INIT;
184 size = 0;
185 }
186 ~DynArray()
187 {
188 if ( mem != pool ) {
189 delete mem;
190 }
191 }
192 void Push( T t )
193 {
194 EnsureCapacity( size+1 );
195 mem[size++] = t;
196 }
197
198 T* PushArr( int count )
199 {
200 EnsureCapacity( size+count );
201 T* ret = &mem[size];
202 size += count;
203 return ret;
204 }
205 T Pop() {
206 return mem[--size];
207 }
208 void PopArr( int count )
209 {
210 TIXMLASSERT( size >= count );
211 size -= count;
212 }
213
U-Stream\Leeae25a442012-02-17 17:48:16 -0800214 bool Empty() const { return size == 0; }
215 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
216 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
217 int Size() const { return size; }
218 int Capacity() const { return allocated; }
219 const T* Mem() const { return mem; }
220 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800221
222
223private:
224 void EnsureCapacity( int cap ) {
225 if ( cap > allocated ) {
226 int newAllocated = cap * 2;
227 T* newMem = new T[newAllocated];
228 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
229 if ( mem != pool ) delete [] mem;
230 mem = newMem;
231 allocated = newAllocated;
232 }
233 }
234
235 T* mem;
236 T pool[INIT];
237 int allocated; // objects allocated
238 int size; // number objects in use
239};
240
Lee Thomason50adb4c2012-02-13 15:07:09 -0800241
U-Stream\Leeae25a442012-02-17 17:48:16 -0800242/*
243 Parent virtual class a a pool for fast allocation
244 and deallocation of objects.
245*/
Lee Thomasond1983222012-02-06 08:41:24 -0800246class MemPool
247{
248public:
249 MemPool() {}
250 virtual ~MemPool() {}
251
252 virtual int ItemSize() const = 0;
253 virtual void* Alloc() = 0;
254 virtual void Free( void* ) = 0;
255};
256
Lee Thomason50adb4c2012-02-13 15:07:09 -0800257
U-Stream\Leeae25a442012-02-17 17:48:16 -0800258/*
259 Template child class to create pools of the correct type.
260*/
Lee Thomasond1983222012-02-06 08:41:24 -0800261template< int SIZE >
262class MemPoolT : public MemPool
263{
264public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800265 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800266 ~MemPoolT() {
267 // Delete the blocks.
268 for( int i=0; i<blockPtrs.Size(); ++i ) {
269 delete blockPtrs[i];
270 }
271 }
272
273 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800274 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800275
276 virtual void* Alloc() {
277 if ( !root ) {
278 // Need a new block.
279 Block* block = new Block();
280 blockPtrs.Push( block );
281
282 for( int i=0; i<COUNT-1; ++i ) {
283 block->chunk[i].next = &block->chunk[i+1];
284 }
285 block->chunk[COUNT-1].next = 0;
286 root = block->chunk;
287 }
288 void* result = root;
289 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800290
291 ++currentAllocs;
292 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
293 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800294 return result;
295 }
296 virtual void Free( void* mem ) {
297 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800298 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800299 Chunk* chunk = (Chunk*)mem;
300 memset( chunk, 0xfe, sizeof(Chunk) );
301 chunk->next = root;
302 root = chunk;
303 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800304 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800305 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
306 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800307 }
Lee Thomasond1983222012-02-06 08:41:24 -0800308
309private:
310 enum { COUNT = 1024/SIZE };
311 union Chunk {
312 Chunk* next;
313 char mem[SIZE];
314 };
315 struct Block {
316 Chunk chunk[COUNT];
317 };
318 DynArray< Block*, 10 > blockPtrs;
319 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800320
321 int currentAllocs;
322 int nAllocs;
323 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800324};
325
Lee Thomason2c85a712012-01-31 08:24:24 -0800326
Lee Thomason56bdd022012-02-09 18:16:58 -0800327
328/**
329 Implements the interface to the "Visitor pattern" (see the Accept() method.)
330 If you call the Accept() method, it requires being passed a XMLVisitor
331 class to handle callbacks. For nodes that contain other nodes (Document, Element)
332 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
333 are simply called with Visit().
334
335 If you return 'true' from a Visit method, recursive parsing will continue. If you return
336 false, <b>no children of this node or its sibilings</b> will be Visited.
337
338 All flavors of Visit methods have a default implementation that returns 'true' (continue
339 visiting). You need to only override methods that are interesting to you.
340
341 Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
342
343 You should never change the document from a callback.
344
345 @sa XMLNode::Accept()
346*/
347class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800348{
349public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800350 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800351
Lee Thomason56bdd022012-02-09 18:16:58 -0800352 /// Visit a document.
353 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
354 /// Visit a document.
355 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
356
357 /// Visit an element.
358 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
359 /// Visit an element.
360 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
361
362 /// Visit a declaration
Lee Thomason50f97b22012-02-11 16:33:40 -0800363 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800364 /// Visit a text node
365 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
366 /// Visit a comment node
367 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
368 /// Visit an unknown node
Lee Thomason50f97b22012-02-11 16:33:40 -0800369 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800370};
371
372
U-Stream\Leeae25a442012-02-17 17:48:16 -0800373/*
374 Utility functionality.
375*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800376class XMLUtil
377{
Lee Thomasond1983222012-02-06 08:41:24 -0800378public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800379 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
380 // correct, but simple, and usually works.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800381 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
382 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800383
384 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
385 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800386 if ( p == q ) {
387 return true;
388 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800389 while( *p && *q && *p == *q && n<nChar ) {
390 ++p; ++q; ++n;
391 }
392 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
393 return true;
394 }
395 return false;
396 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700397 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800398 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
399 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400
401 static const char* ReadBOM( const char* p, bool* hasBOM );
402 // p is the starting location,
403 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800404 static const char* GetCharacterRef( const char* p, char* value, int* length );
405 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800406};
407
Lee Thomason5cae8972012-01-24 18:03:07 -0800408
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800409/** XMLNode is a base class for every object that is in the
410 XML Document Object Model (DOM), except XMLAttributes.
411 Nodes have siblings, a parent, and children which can
412 be navigated. A node is always in a XMLDocument.
413 The type of a TiXmlNode can be queried, and it can
414 be cast to its more defined type.
415
416 An XMLDocument allocates memory for all its Nodes.
417 When the XMLDocument gets deleted, all its Nodes
418 will also be deleted.
419
420 @verbatim
421 A Document can contain: Element (container or leaf)
422 Comment (leaf)
423 Unknown (leaf)
424 Declaration( leaf )
425
426 An Element can contain: Element (container or leaf)
427 Text (leaf)
428 Attributes (not on tree)
429 Comment (leaf)
430 Unknown (leaf)
431
432 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800433*/
Lee Thomasond1983222012-02-06 08:41:24 -0800434class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800435{
436 friend class XMLDocument;
437 friend class XMLElement;
438public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800439
440 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800441 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800442 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800443 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800444
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800445 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
446 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
447 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
448 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
449 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
450 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800451
Lee Thomason50f97b22012-02-11 16:33:40 -0800452 virtual const XMLElement* ToElement() const { return 0; }
453 virtual const XMLText* ToText() const { return 0; }
454 virtual const XMLComment* ToComment() const { return 0; }
455 virtual const XMLDocument* ToDocument() const { return 0; }
456 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
457 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800458
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800459 /** The meaning of 'value' changes for the specific type.
460 @verbatim
461 Document: empy
462 Element: name of the element
463 Comment: the comment text
464 Unknown: the tag contents
465 Text: the text string
466 @endverbatim
467 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800468 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800469 /** Set the Value of an XML node.
470 @sa Value()
471 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800472 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800474 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800475 const XMLNode* Parent() const { return parent; }
476 XMLNode* Parent() { return parent; }
477
Lee Thomason50f97b22012-02-11 16:33:40 -0800478 /// Returns true if this node has no children.
479 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800480
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800481 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800482 const XMLNode* FirstChild() const { return firstChild; }
483 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800484 /** Get the first child element, or optionally the first child
485 element with the specified name.
486 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800487 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700488 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800489
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800490 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800491 const XMLNode* LastChild() const { return lastChild; }
492 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800493
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800494 /** Get the last child element or optionally the last child
495 element with the specified name.
496 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800497 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700498 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800499
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800500 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800501 const XMLNode* PreviousSibling() const { return prev; }
502 XMLNode* PreviousSibling() { return prev; }
503
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800504 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800505 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason5ce89412012-03-20 13:23:44 -0700506 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800507
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800508 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800509 const XMLNode* NextSibling() const { return next; }
510 XMLNode* NextSibling() { return next; }
511
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800512 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800513 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700514 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800515
Lee Thomason1ff38e02012-02-14 18:18:16 -0800516 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800517 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800518 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800519 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800520
521 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800522 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800523 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800524 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800525 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800526 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800527 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800528 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800529 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
530
U-Stream\Leeae25a442012-02-17 17:48:16 -0800531 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800532 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800533 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800534 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800535
536 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800537 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800538 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800539 void DeleteChild( XMLNode* node );
540
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800541 /**
542 Make a copy of this node, but not its children.
543 You may pass in a Document pointer that will be
544 the owner of the new Node. If the 'document' is
545 null, then the node returned will be allocated
546 from the current Document. (this->GetDocument())
547
548 Note: if called on a XMLDocument, this will return null.
549 */
550 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
551
552 /**
553 Test if 2 nodes are the same, but don't test children.
554 The 2 nodes do not need to be in the same Document.
555
556 Note: if called on a XMLDocument, this will return false.
557 */
558 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
559
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800560 /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
561 XML tree will be conditionally visited and the host will be called back
562 via the TiXmlVisitor interface.
563
564 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
565 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
566 interface versus any other.)
567
568 The interface has been based on ideas from:
569
570 - http://www.saxproject.org/
571 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
572
573 Which are both good references for "visiting".
574
575 An example of using Accept():
576 @verbatim
577 TiXmlPrinter printer;
578 tinyxmlDoc.Accept( &printer );
579 const char* xmlcstr = printer.CStr();
580 @endverbatim
581 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800582 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800583
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800584 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800585 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800586
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587protected:
588 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800589 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800590 XMLNode( const XMLNode& ); // not supported
591 void operator=( const XMLNode& ); // not supported
Lee Thomasond1983222012-02-06 08:41:24 -0800592
Lee Thomason3f57d272012-01-11 15:30:03 -0800593 XMLDocument* document;
594 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800595 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800596
597 XMLNode* firstChild;
598 XMLNode* lastChild;
599
600 XMLNode* prev;
601 XMLNode* next;
602
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800603private:
Lee Thomasond1983222012-02-06 08:41:24 -0800604 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800605 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800606};
607
608
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800609/** XML text.
610
611 Note that a text node can have child element nodes, for example:
612 @verbatim
613 <root>This is <b>bold</b></root>
614 @endverbatim
615
616 A text node can have 2 ways to output the next. "normal" output
617 and CDATA. It will default to the mode it was parsed from the XML file and
618 you generally want to leave it alone, but you can change the output mode with
619 SetCDATA() and query it with CDATA().
620*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800621class XMLText : public XMLNode
622{
Lee Thomason2c85a712012-01-31 08:24:24 -0800623 friend class XMLBase;
624 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800625public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800626 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800627
Lee Thomason751da522012-02-10 08:50:51 -0800628 virtual XMLText* ToText() { return this; }
629 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800630
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800631 /// Declare whether this should be CDATA or standard text.
Lee Thomason5ce89412012-03-20 13:23:44 -0700632 void SetCData( bool _isCData ) { this->isCData = _isCData; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800633 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800634 bool CData() const { return isCData; }
635
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800636 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800637 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
638 virtual bool ShallowEqual( const XMLNode* compare ) const;
639
Lee Thomason5492a1c2012-01-23 15:32:10 -0800640
641protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800642 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
643 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800644 XMLText( const XMLText& ); // not supported
645 void operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800646
647private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800648 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800649};
650
651
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800652/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800653class XMLComment : public XMLNode
654{
Lee Thomason2c85a712012-01-31 08:24:24 -0800655 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800656public:
Lee Thomason751da522012-02-10 08:50:51 -0800657 virtual XMLComment* ToComment() { return this; }
658 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800659
Lee Thomason56bdd022012-02-09 18:16:58 -0800660 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800662 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800663 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
664 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800665
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800666protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800667 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800668 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800669 XMLComment( const XMLComment& ); // not supported
670 void operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671
Lee Thomason3f57d272012-01-11 15:30:03 -0800672private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800673};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800674
675
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800676/** In correct XML the declaration is the first entry in the file.
677 @verbatim
678 <?xml version="1.0" standalone="yes"?>
679 @endverbatim
680
681 TinyXML2 will happily read or write files without a declaration,
682 however.
683
684 The text of the declaration isn't interpreted. It is parsed
685 and written as a string.
686*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800687class XMLDeclaration : public XMLNode
688{
689 friend class XMLDocument;
690public:
691 virtual XMLDeclaration* ToDeclaration() { return this; }
692 virtual const XMLDeclaration* ToDeclaration() const { return this; }
693
694 virtual bool Accept( XMLVisitor* visitor ) const;
695
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800696 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800697 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
698 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800699
700protected:
701 XMLDeclaration( XMLDocument* doc );
702 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800703 XMLDeclaration( const XMLDeclaration& ); // not supported
704 void operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800705};
706
707
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800708/** Any tag that tinyXml doesn't recognize is saved as an
709 unknown. It is a tag of text, but should not be modified.
710 It will be written back to the XML, unchanged, when the file
711 is saved.
712
713 DTD tags get thrown into TiXmlUnknowns.
714*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800715class XMLUnknown : public XMLNode
716{
717 friend class XMLDocument;
718public:
719 virtual XMLUnknown* ToUnknown() { return this; }
720 virtual const XMLUnknown* ToUnknown() const { return this; }
721
722 virtual bool Accept( XMLVisitor* visitor ) const;
723
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800724 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800725 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
726 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800727
728protected:
729 XMLUnknown( XMLDocument* doc );
730 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800731 XMLUnknown( const XMLUnknown& ); // not supported
732 void operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800733};
734
735
Lee Thomason1ff38e02012-02-14 18:18:16 -0800736enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800737 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800738 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800739
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700740 XML_NO_ATTRIBUTE,
741 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800742
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700743 XML_ERROR_FILE_NOT_FOUND,
Lee Thomason7f7b1622012-03-24 12:49:03 -0700744 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700745 XML_ERROR_ELEMENT_MISMATCH,
746 XML_ERROR_PARSING_ELEMENT,
747 XML_ERROR_PARSING_ATTRIBUTE,
748 XML_ERROR_IDENTIFYING_TAG,
749 XML_ERROR_PARSING_TEXT,
750 XML_ERROR_PARSING_CDATA,
751 XML_ERROR_PARSING_COMMENT,
752 XML_ERROR_PARSING_DECLARATION,
753 XML_ERROR_PARSING_UNKNOWN,
754 XML_ERROR_EMPTY_DOCUMENT,
755 XML_ERROR_MISMATCHED_ELEMENT,
756 XML_ERROR_PARSING
Lee Thomason1ff38e02012-02-14 18:18:16 -0800757};
758
759
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800760/** An attribute is a name-value pair. Elements have an arbitrary
761 number of attributes, each with a unique name.
762
763 @note The attributes are not XMLNodes. You may only query the
764 Next() attribute in a list.
765*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800766class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800767{
768 friend class XMLElement;
769public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800770 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
771 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
772 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800773
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800774 /** IntAttribute interprets the attribute as an integer, and returns the value.
775 If the value isn't an integer, 0 will be returned. There is no error checking;
776 use QueryIntAttribute() if you need error checking.
777 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800778 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800779 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800780 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800781 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800783 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800784 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800785 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800786 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
789 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700790 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800791 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800795 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800796 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800797 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800798 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800799 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800800 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800801
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800802 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800803 void SetAttribute( const char* 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( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800806 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800807 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800808 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800809 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800810 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800811 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800812 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800813 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800814
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800815private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800816 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800817
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800818 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800819 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800820 XMLAttribute( const XMLAttribute& ); // not supported
821 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800822 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800823
Lee Thomason6f381b72012-03-02 12:59:39 -0800824 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800825
Lee Thomason751da522012-02-10 08:50:51 -0800826 mutable StrPair name;
827 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800828 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800829 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800830};
831
832
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800833/** The element is a container class. It has a value, the element name,
834 and can contain other elements, text, comments, and unknowns.
835 Elements also contain an arbitrary number of attributes.
836*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800837class XMLElement : public XMLNode
838{
Lee Thomason2c85a712012-01-31 08:24:24 -0800839 friend class XMLBase;
840 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800841public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800842 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800843 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800844 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800845 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800846
Lee Thomason751da522012-02-10 08:50:51 -0800847 virtual XMLElement* ToElement() { return this; }
848 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800849 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800850
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800851 /** Given an attribute name, Attribute() returns the value
Lee Thomason92258152012-03-24 13:05:39 -0700852 for the attribute of that name, or null if none
853 exists. For example:
854
855 @verbatim
856 const char* value = ele->Attribute( "foo" );
857 @endverbatim
858
859 The 'value' parameter is normally null. However, if specified,
860 the attribute will only be returned if the 'name' and 'value'
861 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700862
863 @verbatim
864 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
865 @endverbatim
866
867 rather than:
868 @verbatim
869 if ( ele->Attribute( "foo" ) ) {
870 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
871 }
872 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800873 */
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700874 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800875
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800876 /** Given an attribute name, IntAttribute() returns the value
877 of the attribute interpreted as an integer. 0 will be
878 returned if there is an error. For a method with error
879 checking, see QueryIntAttribute()
880 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800881 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800882 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800883 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800884 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800885 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800886 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800887 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800888 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800889 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
890
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800891 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700892 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
893 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800894 doesn't exist. If successful, the result of the conversion
895 will be written to 'value'. If not successful, nothing will
896 be written to 'value'. This allows you to provide default
897 value:
898
899 @verbatim
900 int value = 10;
901 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
902 @endverbatim
903 */
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700904 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 -0800905 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700906 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 -0800907 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700908 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 -0800909 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700910 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 -0800911 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700912 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 -0800913
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800914 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700915 void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800916 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700917 void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800918 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700919 void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800920 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700921 void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800922 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700923 void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800924
U-Stream\Leeae25a442012-02-17 17:48:16 -0800925 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800926 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800927 */
928 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800929
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800930 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800931 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800932 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800933 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800934
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800935 /** Convenience function for easy access to the text inside an element. Although easy
936 and concise, GetText() is limited compared to getting the TiXmlText child
937 and accessing it directly.
938
939 If the first child of 'this' is a TiXmlText, the GetText()
940 returns the character string of the Text node, else null is returned.
941
942 This is a convenient method for getting the text of simple contained text:
943 @verbatim
944 <foo>This is text</foo>
945 const char* str = fooElement->GetText();
946 @endverbatim
947
948 'str' will be a pointer to "This is text".
949
950 Note that this function can be misleading. If the element foo was created from
951 this XML:
952 @verbatim
953 <foo><b>This is text</b></foo>
954 @endverbatim
955
956 then the value of str would be null. The first child node isn't a text node, it is
957 another element. From this XML:
958 @verbatim
959 <foo>This is <b>text</b></foo>
960 @endverbatim
961 GetText() will return "This is ".
962 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800963 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800964
Lee Thomason2c85a712012-01-31 08:24:24 -0800965 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 enum {
967 OPEN, // <foo>
968 CLOSED, // <foo/>
969 CLOSING // </foo>
970 };
971 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800972 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
974 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800975
Lee Thomason50adb4c2012-02-13 15:07:09 -0800976private:
Lee Thomason2c85a712012-01-31 08:24:24 -0800977 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800978 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800979 XMLElement( const XMLElement& ); // not supported
980 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800981
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800982 XMLAttribute* FindAttribute( const char* name );
983 XMLAttribute* FindOrCreateAttribute( const char* name );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800984 void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -0800986
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987 int closingType;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800988 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800989};
990
991
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800992/** A document binds together all the functionality.
993 It can be saved, loaded, and printed to the screen.
994 All Nodes are connected and allocated to a Document.
995 If the Document is deleted, all its Nodes are also deleted.
996*/
Lee Thomason67d61312012-01-24 16:01:51 -0800997class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800998{
Lee Thomasond1983222012-02-06 08:41:24 -0800999 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001000public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001001 /// constructor
Lee Thomason6f381b72012-03-02 12:59:39 -08001002 XMLDocument( bool processEntities = true );
Lee Thomason3f57d272012-01-11 15:30:03 -08001003 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001004
Lee Thomason751da522012-02-10 08:50:51 -08001005 virtual XMLDocument* ToDocument() { return this; }
1006 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -08001007
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001008 /**
1009 Parse an XML file from a character string.
1010 Returns XML_NO_ERROR (0) on success, or
1011 an errorID.
1012 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001013 int Parse( const char* xml );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001014 /**
1015 Load an XML file from disk.
1016 Returns XML_NO_ERROR (0) on success, or
1017 an errorID.
1018 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001019 int LoadFile( const char* filename );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001020 /**
1021 Load an XML file from disk. You are responsible
1022 for providing and closing the FILE*.
1023
1024 Returns XML_NO_ERROR (0) on success, or
1025 an errorID.
1026 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001027 int LoadFile( FILE* );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001028 /**
1029 Save the XML file to disk.
1030 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001031 void SaveFile( const char* filename );
1032
Lee Thomason6f381b72012-03-02 12:59:39 -08001033 bool ProcessEntities() const { return processEntities; }
1034
1035 /**
1036 Returns true if this document has a leading Byte Order Mark of UTF8.
1037 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001038 bool HasBOM() const { return writeBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001039
1040 /** Return the root element of DOM. Equivalent to FirstChildElement().
1041 To get the first node, use FirstChild().
1042 */
Lee Thomasond6277762012-02-22 16:00:12 -08001043 XMLElement* RootElement() { return FirstChildElement(); }
1044 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001046 /** Print the Document. If the Printer is not provided, it will
1047 print to stdout. If you provide Printer, this can print to a file:
1048 @verbatim
1049 XMLPrinter printer( fp );
1050 doc.Print( &printer );
1051 @endverbatim
1052
1053 Or you can use a printer to print to memory:
1054 @verbatim
1055 XMLPrinter printer;
1056 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001057 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001058 @endverbatim
1059 */
1060 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001061 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001062
Lee Thomason1ff38e02012-02-14 18:18:16 -08001063 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001064 Create a new Element associated with
1065 this Document. The memory for the Element
1066 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001067 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001068 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001069 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001070 Create a new Comment associated with
1071 this Document. The memory for the Comment
1072 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001073 */
1074 XMLComment* NewComment( const char* comment );
1075 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001076 Create a new Text associated with
1077 this Document. The memory for the Text
1078 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001079 */
1080 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001081 /**
1082 Create a new Declaration associated with
1083 this Document. The memory for the object
1084 is managed by the Document.
1085 */
1086 XMLDeclaration* NewDeclaration( const char* text );
1087 /**
1088 Create a new Unknown associated with
1089 this Document. The memory for the object
1090 is managed by the Document.
1091 */
1092 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001093
U-Stream\Leeae25a442012-02-17 17:48:16 -08001094 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001095 Delete a node associated with this documented.
1096 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001097 */
1098 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1099
Lee Thomason67d61312012-01-24 16:01:51 -08001100 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001101
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001102 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001103 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001104 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001105 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001106 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001107 const char* GetErrorStr1() const { return errorStr1; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001108 /// Return possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001109 const char* GetErrorStr2() const { return errorStr2; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001110 /// If there is an error, print it to stdout
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001111 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001112
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001113 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001114 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001115
Lee Thomason6f381b72012-03-02 12:59:39 -08001116 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1117 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001118
Lee Thomason3f57d272012-01-11 15:30:03 -08001119private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001120 XMLDocument( const XMLDocument& ); // not supported
1121 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001122 void InitDocument();
1123
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001124 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001125 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001126 int errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001127 const char* errorStr1;
1128 const char* errorStr2;
1129 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001130
1131 MemPoolT< sizeof(XMLElement) > elementPool;
1132 MemPoolT< sizeof(XMLAttribute) > attributePool;
1133 MemPoolT< sizeof(XMLText) > textPool;
1134 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001135};
1136
Lee Thomason7c913cd2012-01-26 18:32:34 -08001137
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001138
1139/**
1140 Printing functionality. The XMLPrinter gives you more
1141 options than the XMLDocument::Print() method.
1142
1143 It can:
1144 -# Print to memory.
1145 -# Print to a file you provide
1146 -# Print XML without a XMLDocument.
1147
1148 Print to Memory
1149
1150 @verbatim
1151 XMLPrinter printer;
1152 doc->Print( &printer );
1153 SomeFunctior( printer.CStr() );
1154 @endverbatim
1155
1156 Print to a File
1157
1158 You provide the file pointer.
1159 @verbatim
1160 XMLPrinter printer( fp );
1161 doc.Print( &printer );
1162 @endverbatim
1163
1164 Print without a XMLDocument
1165
1166 When loading, an XML parser is very useful. However, sometimes
1167 when saving, it just gets in the way. The code is often set up
1168 for streaming, and constructing the DOM is just overhead.
1169
1170 The Printer supports the streaming case. The following code
1171 prints out a trivially simple XML file without ever creating
1172 an XML document.
1173
1174 @verbatim
1175 XMLPrinter printer( fp );
1176 printer.OpenElement( "foo" );
1177 printer.PushAttribute( "foo", "bar" );
1178 printer.CloseElement();
1179 @endverbatim
1180*/
1181class XMLPrinter : public XMLVisitor
Lee Thomason5cae8972012-01-24 18:03:07 -08001182{
1183public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001184 /** Construct the printer. If the FILE* is specified,
1185 this will print to the FILE. Else it will print
1186 to memory, and the result is available in CStr()
1187 */
1188 XMLPrinter( FILE* file=0 );
1189 ~XMLPrinter() {}
Lee Thomason5cae8972012-01-24 18:03:07 -08001190
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001191 /** If streaming, write the BOM and declaration. */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001192 void PushHeader( bool writeBOM, bool writeDeclaration );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001193 /** If streaming, start writing an element.
1194 The element must be closed with CloseElement()
1195 */
Lee Thomason56bdd022012-02-09 18:16:58 -08001196 void OpenElement( const char* name );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001197 /// If streaming, add an attribute to an open element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001198 void PushAttribute( const char* name, const char* value );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001199 void PushAttribute( const char* name, int value );
1200 void PushAttribute( const char* name, unsigned value );
1201 void PushAttribute( const char* name, bool value );
1202 void PushAttribute( const char* name, double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001203 /// If streaming, close the Element.
Lee Thomason5cae8972012-01-24 18:03:07 -08001204 void CloseElement();
1205
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001206 /// Add a text node.
Lee Thomason50f97b22012-02-11 16:33:40 -08001207 void PushText( const char* text, bool cdata=false );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001208 /// Add a comment
Lee Thomason5cae8972012-01-24 18:03:07 -08001209 void PushComment( const char* comment );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001210
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001211 void PushDeclaration( const char* value );
1212 void PushUnknown( const char* value );
Lee Thomason5cae8972012-01-24 18:03:07 -08001213
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001214 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
Lee Thomason751da522012-02-10 08:50:51 -08001215 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1216
1217 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1218 virtual bool VisitExit( const XMLElement& element );
1219
1220 virtual bool Visit( const XMLText& text );
1221 virtual bool Visit( const XMLComment& comment );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001222 virtual bool Visit( const XMLDeclaration& declaration );
1223 virtual bool Visit( const XMLUnknown& unknown );
Lee Thomason751da522012-02-10 08:50:51 -08001224
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001225 /**
1226 If in print to memory mode, return a pointer to
1227 the XML file in memory.
1228 */
U-Stream\Leeae25a442012-02-17 17:48:16 -08001229 const char* CStr() const { return buffer.Mem(); }
Lee Thomason751da522012-02-10 08:50:51 -08001230
Lee Thomason5cae8972012-01-24 18:03:07 -08001231private:
1232 void SealElement();
1233 void PrintSpace( int depth );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001234 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001235 void Print( const char* format, ... );
Lee Thomason5cae8972012-01-24 18:03:07 -08001236
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001237 bool elementJustOpened;
1238 bool firstElement;
Lee Thomason5cae8972012-01-24 18:03:07 -08001239 FILE* fp;
1240 int depth;
Lee Thomason56bdd022012-02-09 18:16:58 -08001241 int textDepth;
Lee Thomason6f381b72012-03-02 12:59:39 -08001242 bool processEntities;
Lee Thomason56bdd022012-02-09 18:16:58 -08001243
Lee Thomason857b8682012-01-25 17:50:25 -08001244 enum {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245 ENTITY_RANGE = 64,
1246 BUF_SIZE = 200
Lee Thomason857b8682012-01-25 17:50:25 -08001247 };
1248 bool entityFlag[ENTITY_RANGE];
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001249 bool restrictedEntityFlag[ENTITY_RANGE];
Lee Thomason5cae8972012-01-24 18:03:07 -08001250
Lee Thomason2c85a712012-01-31 08:24:24 -08001251 DynArray< const char*, 10 > stack;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001252 DynArray< char, 20 > buffer, accumulator;
Lee Thomason5cae8972012-01-24 18:03:07 -08001253};
1254
1255
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001256} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001257
U-Lama\Lee560bd472011-12-28 19:42:49 -08001258
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -07001259// What follows is the docs for the examples.
1260// I'd like the docs to be just before the
1261// actual examples in xmltest.cpp, but I
1262// can't seem to get doxygen to do that. It
1263// would be a wonderful patch if anyone figures
1264// it out.
1265
1266/** @page Example-1 Load an XML File
1267 * @dontinclude ./xmltest.cpp
1268 * Basic XML file loading.
1269 * The basic syntax to load an XML file from
1270 * disk and check for an error. (ErrorID()
1271 * will return 0 for no error.)
1272 * @skip example_1()
1273 * @until }
1274 */
1275
1276
1277/** @page Example-2 Parse an XML from char buffer
1278 * @dontinclude ./xmltest.cpp
1279 * Basic XML string parsing.
1280 * The basic syntax to parse an XML for
1281 * a char* and check for an error. (ErrorID()
1282 * will return 0 for no error.)
1283 * @skip example_2()
1284 * @until }
1285 */
1286
1287/** @page Example-3 Get information out of XML
1288 @dontinclude ./xmltest.cpp
1289 In this example, we navigate a simple XML
1290 file, and read some interesting text. Note
1291 that this is examlpe doesn't use error
1292 checking; working code should check for null
1293 pointers when walking an XML tree, or use
1294 XMLHandle.
1295
1296 (The XML is an excerpt from "dream.xml").
1297
1298 @skip example_3
1299 @until </PLAY>";
1300
1301 The structure of the XML file is:
1302
1303 <ul>
1304 <li>(declaration)</li>
1305 <li>(dtd stuff)</li>
1306 <li>Element "PLAY"</li>
1307 <ul>
1308 <li>Element "TITLE"</li>
1309 <ul>
1310 <li>Text "A Midsummer Night's Dream"</li>
1311 </ul>
1312 </ul>
1313 </ul>
1314
1315 For this example, we want to print out the
1316 title of the play. The text of the title (what
1317 we want) is child of the "TITLE" element which
1318 is a child of the "PLAY" element.
1319
1320 We want to skip the declaration and dtd, so the
1321 method FirstChildElement() is a good choice. The
1322 FirstChildElement() of the Document is the "PLAY"
1323 Element, the FirstChildElement() of the "PLAY" Element
1324 is the "TITLE" Element.
1325
1326 @until ( "TITLE" );
1327
1328 We can then use the convenience function GetText()
1329 to get the title of the play.
1330
1331 @until title );
1332
1333 Text is just another Node in the XML DOM. And in
1334 fact you should be a little cautious with it, as
1335 text nodes can contain elements.
1336
1337 @verbatim
1338 Consider: A Midsummer Night's <b>Dream</b>
1339 @endverbatim
1340
1341 It is more correct to actually query the Text Node
1342 if in doubt:
1343
1344 @until title );
1345
1346 Noting that here we use FirstChild() since we are
1347 looking for XMLText, not an element, and ToText()
1348 is a cast from a Node to a XMLText.
1349*/
U-Lama\Lee560bd472011-12-28 19:42:49 -08001350
U-Stream\Leeae25a442012-02-17 17:48:16 -08001351#endif // TINYXML2_INCLUDED