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