blob: bd504fc1ecf0d6db2d68e5711a259fc063ccf3a6 [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
Jerome Martinez242c3ea2013-01-06 12:20:04 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <ctype.h>
29# include <limits.h>
30# include <stdio.h>
31# include <stdlib.h>
32# include <string.h>
33# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070034#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070035# include <cctype>
36# include <climits>
37# include <cstdio>
38# include <cstdlib>
39# include <cstring>
40# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070041#endif
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070042
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070043/*
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/*
Lee Thomasona9cf3f92012-10-11 16:56:51 -070047 gcc:
Lee Thomason5b0a6772012-11-19 13:54:42 -080048 g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
MortenMacFly4ee49f12013-01-14 20:03:14 +010049
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 Formatting, Artistic Style:
51 AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080052*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080053
U-Lama\Lee4cee6112011-12-31 14:58:18 -080054#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070055# ifndef DEBUG
56# define DEBUG
57# endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080058#endif
59
60
61#if defined(DEBUG)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070062# if defined(_MSC_VER)
63# define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
64# elif defined (ANDROID_NDK)
65# include <android/log.h>
66# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
67# else
68# include <assert.h>
69# define TIXMLASSERT assert
70# endif
71# else
72# define TIXMLASSERT( x ) {}
U-Lama\Lee4cee6112011-12-31 14:58:18 -080073#endif
74
U-Lama\Leee13c3e62011-12-28 14:36:55 -080075
Lee Thomason1a1d4a72012-02-15 09:09:25 -080076#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
Lee Thomasona9cf3f92012-10-11 16:56:51 -070077// Microsoft visual studio, version 2005 and higher.
78/*int _snprintf_s(
79 char *buffer,
80 size_t sizeOfBuffer,
81 size_t count,
82 const char *format [,
83 argument] ...
84);*/
85inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
86{
87 va_list va;
88 va_start( va, format );
89 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
90 va_end( va );
91 return result;
92}
93#define TIXML_SSCANF sscanf_s
Lee Thomason (grinliz)b9e791f2012-04-06 21:27:10 -070094#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070095// GCC version 3 and higher
96//#warning( "Using sn* functions." )
97#define TIXML_SNPRINTF snprintf
98#define TIXML_SSCANF sscanf
Lee Thomason1a1d4a72012-02-15 09:09:25 -080099#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -0800100
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -0800101static const int TIXML2_MAJOR_VERSION = 1;
102static const int TIXML2_MINOR_VERSION = 0;
103static const int TIXML2_PATCH_VERSION = 10;
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 Thomasona9cf3f92012-10-11 16:56:51 -0700127 enum {
128 NEEDS_ENTITY_PROCESSING = 0x01,
129 NEEDS_NEWLINE_NORMALIZATION = 0x02,
130 COLLAPSE_WHITESPACE = 0x04,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800131
Lee Thomason624d43f2012-10-12 10:58:48 -0700132 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason624d43f2012-10-12 10:58:48 -0700134 ATTRIBUTE_NAME = 0,
135 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
136 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
137 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700138 };
Lee Thomason39ede242012-01-20 11:27:56 -0800139
Lee Thomason120b3a62012-10-12 10:06:59 -0700140 StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 ~StrPair();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomason120b3a62012-10-12 10:06:59 -0700143 void Set( char* start, char* end, int flags ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700144 Reset();
Lee Thomason120b3a62012-10-12 10:06:59 -0700145 _start = start;
146 _end = end;
147 _flags = flags | NEEDS_FLUSH;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700148 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 const char* GetStr();
Lee Thomason120b3a62012-10-12 10:06:59 -0700151
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700152 bool Empty() const {
Lee Thomason120b3a62012-10-12 10:06:59 -0700153 return _start == _end;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700154 }
Lee Thomason39ede242012-01-20 11:27:56 -0800155
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700156 void SetInternedStr( const char* str ) {
157 Reset();
Lee Thomason120b3a62012-10-12 10:06:59 -0700158 _start = const_cast<char*>(str);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700159 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700160
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700161 void SetStr( const char* str, int flags=0 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800162
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700163 char* ParseText( char* in, const char* endTag, int strFlags );
164 char* ParseName( char* in );
Lee Thomason56bdd022012-02-09 18:16:58 -0800165
Lee Thomason39ede242012-01-20 11:27:56 -0800166private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700167 void Reset();
168 void CollapseWhitespace();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700170 enum {
171 NEEDS_FLUSH = 0x100,
172 NEEDS_DELETE = 0x200
173 };
Lee Thomasone4422302012-01-20 17:59:50 -0800174
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700175 // After parsing, if *end != 0, it can be set to zero.
Lee Thomason120b3a62012-10-12 10:06:59 -0700176 int _flags;
177 char* _start;
178 char* _end;
Lee Thomason39ede242012-01-20 11:27:56 -0800179};
180
U-Lama\Lee560bd472011-12-28 19:42:49 -0800181
U-Stream\Leeae25a442012-02-17 17:48:16 -0800182/*
183 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
184 Has a small initial memory pool, so that low or no usage will not
185 cause a call to new/delete
186*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800187template <class T, int INIT>
188class DynArray
189{
190public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700191 DynArray< T, INIT >() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700192 _mem = _pool;
193 _allocated = INIT;
194 _size = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700196
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 ~DynArray() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700198 if ( _mem != _pool ) {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700199 delete [] _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 }
201 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 void Push( T t ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700204 EnsureCapacity( _size+1 );
205 _mem[_size++] = t;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800207
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700208 T* PushArr( int count ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700209 EnsureCapacity( _size+count );
210 T* ret = &_mem[_size];
211 _size += count;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 return ret;
213 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700214
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 T Pop() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700216 return _mem[--_size];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700217 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700218
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700219 void PopArr( int count ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700220 TIXMLASSERT( _size >= count );
221 _size -= count;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800223
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700224 bool Empty() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700225 return _size == 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700226 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700227
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700228 T& operator[](int i) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700229 TIXMLASSERT( i>= 0 && i < _size );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700230 return _mem[i];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700232
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700233 const T& operator[](int i) const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700234 TIXMLASSERT( i>= 0 && i < _size );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700235 return _mem[i];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700237
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700238 int Size() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700239 return _size;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700240 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700241
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 int Capacity() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700243 return _allocated;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700244 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700245
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700246 const T* Mem() const {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700247 return _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700249
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700250 T* Mem() {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700251 return _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800253
Lee Thomason2c85a712012-01-31 08:24:24 -0800254private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 void EnsureCapacity( int cap ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700256 if ( cap > _allocated ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700257 int newAllocated = cap * 2;
258 T* newMem = new T[newAllocated];
Lee Thomason624d43f2012-10-12 10:58:48 -0700259 memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
260 if ( _mem != _pool ) {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700261 delete [] _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700262 }
Lee Thomasoned5c8792012-10-12 10:09:48 -0700263 _mem = newMem;
Lee Thomason624d43f2012-10-12 10:58:48 -0700264 _allocated = newAllocated;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700265 }
266 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800267
Lee Thomason624d43f2012-10-12 10:58:48 -0700268 T* _mem;
269 T _pool[INIT];
270 int _allocated; // objects allocated
271 int _size; // number objects in use
Lee Thomason2c85a712012-01-31 08:24:24 -0800272};
273
Lee Thomason50adb4c2012-02-13 15:07:09 -0800274
U-Stream\Leeae25a442012-02-17 17:48:16 -0800275/*
Thomas Roß08bdf502012-05-12 14:21:23 +0200276 Parent virtual class of a pool for fast allocation
U-Stream\Leeae25a442012-02-17 17:48:16 -0800277 and deallocation of objects.
278*/
Lee Thomasond1983222012-02-06 08:41:24 -0800279class MemPool
280{
281public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700282 MemPool() {}
283 virtual ~MemPool() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800284
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 virtual int ItemSize() const = 0;
286 virtual void* Alloc() = 0;
287 virtual void Free( void* ) = 0;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800288 virtual void SetTracked() = 0;
Lee Thomasond1983222012-02-06 08:41:24 -0800289};
290
Lee Thomason50adb4c2012-02-13 15:07:09 -0800291
U-Stream\Leeae25a442012-02-17 17:48:16 -0800292/*
293 Template child class to create pools of the correct type.
294*/
Lee Thomasond1983222012-02-06 08:41:24 -0800295template< int SIZE >
296class MemPoolT : public MemPool
297{
298public:
Lee Thomason5b0a6772012-11-19 13:54:42 -0800299 MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 ~MemPoolT() {
301 // Delete the blocks.
Lee Thomason624d43f2012-10-12 10:58:48 -0700302 for( int i=0; i<_blockPtrs.Size(); ++i ) {
303 delete _blockPtrs[i];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 }
305 }
Lee Thomasond1983222012-02-06 08:41:24 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 virtual int ItemSize() const {
308 return SIZE;
309 }
310 int CurrentAllocs() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700311 return _currentAllocs;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700312 }
Lee Thomasond1983222012-02-06 08:41:24 -0800313
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700314 virtual void* Alloc() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700315 if ( !_root ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 // Need a new block.
317 Block* block = new Block();
Lee Thomason624d43f2012-10-12 10:58:48 -0700318 _blockPtrs.Push( block );
Lee Thomasond1983222012-02-06 08:41:24 -0800319
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700320 for( int i=0; i<COUNT-1; ++i ) {
321 block->chunk[i].next = &block->chunk[i+1];
322 }
323 block->chunk[COUNT-1].next = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700324 _root = block->chunk;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700326 void* result = _root;
327 _root = _root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800328
Lee Thomason624d43f2012-10-12 10:58:48 -0700329 ++_currentAllocs;
330 if ( _currentAllocs > _maxAllocs ) {
331 _maxAllocs = _currentAllocs;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700333 _nAllocs++;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800334 _nUntracked++;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 return result;
336 }
337 virtual void Free( void* mem ) {
338 if ( !mem ) {
339 return;
340 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700341 --_currentAllocs;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 Chunk* chunk = (Chunk*)mem;
Lee Thomason (grinliz)6020a012012-09-08 21:15:09 -0700343#ifdef DEBUG
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700344 memset( chunk, 0xfe, sizeof(Chunk) );
Lee Thomason (grinliz)6020a012012-09-08 21:15:09 -0700345#endif
Lee Thomason624d43f2012-10-12 10:58:48 -0700346 chunk->next = _root;
347 _root = chunk;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700348 }
349 void Trace( const char* name ) {
350 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
Lee Thomason624d43f2012-10-12 10:58:48 -0700351 name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 }
Lee Thomasond1983222012-02-06 08:41:24 -0800353
Lee Thomason5b0a6772012-11-19 13:54:42 -0800354 void SetTracked() {
355 _nUntracked--;
356 }
357
358 int Untracked() const {
359 return _nUntracked;
360 }
361
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -0800362 // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
363 // The test file is large, 170k.
364 // Release: VS2010 gcc(no opt)
365 // 1k: 4000
366 // 2k: 4000
367 // 4k: 3900 21000
368 // 16k: 5200
369 // 32k: 4300
370 // 64k: 4000 21000
371 enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
Jerome Martinez7921df12012-10-24 11:45:44 +0200372
Lee Thomasond1983222012-02-06 08:41:24 -0800373private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700374 union Chunk {
Lee Thomason624d43f2012-10-12 10:58:48 -0700375 Chunk* next;
376 char mem[SIZE];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 };
378 struct Block {
Lee Thomason (grinliz)856da212012-10-19 09:08:15 -0700379 Chunk chunk[COUNT];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700380 };
Lee Thomason624d43f2012-10-12 10:58:48 -0700381 DynArray< Block*, 10 > _blockPtrs;
382 Chunk* _root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800383
Lee Thomason624d43f2012-10-12 10:58:48 -0700384 int _currentAllocs;
385 int _nAllocs;
386 int _maxAllocs;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800387 int _nUntracked;
Lee Thomasond1983222012-02-06 08:41:24 -0800388};
389
Lee Thomason2c85a712012-01-31 08:24:24 -0800390
Lee Thomason56bdd022012-02-09 18:16:58 -0800391
392/**
393 Implements the interface to the "Visitor pattern" (see the Accept() method.)
394 If you call the Accept() method, it requires being passed a XMLVisitor
395 class to handle callbacks. For nodes that contain other nodes (Document, Element)
Thomas Roß08bdf502012-05-12 14:21:23 +0200396 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
Lee Thomason56bdd022012-02-09 18:16:58 -0800397 are simply called with Visit().
398
399 If you return 'true' from a Visit method, recursive parsing will continue. If you return
Thomas Roß08bdf502012-05-12 14:21:23 +0200400 false, <b>no children of this node or its sibilings</b> will be visited.
Lee Thomason56bdd022012-02-09 18:16:58 -0800401
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700402 All flavors of Visit methods have a default implementation that returns 'true' (continue
Lee Thomason56bdd022012-02-09 18:16:58 -0800403 visiting). You need to only override methods that are interesting to you.
404
Thomas Roß08bdf502012-05-12 14:21:23 +0200405 Generally Accept() is called on the TiXmlDocument, although all nodes support visiting.
Lee Thomason56bdd022012-02-09 18:16:58 -0800406
407 You should never change the document from a callback.
408
409 @sa XMLNode::Accept()
410*/
411class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800412{
413public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800415
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 /// Visit a document.
417 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
418 return true;
419 }
420 /// Visit a document.
421 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
422 return true;
423 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 /// Visit an element.
426 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
427 return true;
428 }
429 /// Visit an element.
430 virtual bool VisitExit( const XMLElement& /*element*/ ) {
431 return true;
432 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800433
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 /// Visit a declaration.
435 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
436 return true;
437 }
438 /// Visit a text node.
439 virtual bool Visit( const XMLText& /*text*/ ) {
440 return true;
441 }
442 /// Visit a comment node.
443 virtual bool Visit( const XMLComment& /*comment*/ ) {
444 return true;
445 }
446 /// Visit an unknown node.
447 virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
448 return true;
449 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800450};
451
452
U-Stream\Leeae25a442012-02-17 17:48:16 -0800453/*
454 Utility functionality.
455*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800456class XMLUtil
457{
Lee Thomasond1983222012-02-06 08:41:24 -0800458public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
460 // correct, but simple, and usually works.
461 static const char* SkipWhiteSpace( const char* p ) {
Jerome Martinez242c3ea2013-01-06 12:20:04 +0100462 while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 ++p;
464 }
465 return p;
466 }
467 static char* SkipWhiteSpace( char* p ) {
Jerome Martinez242c3ea2013-01-06 12:20:04 +0100468 while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 ++p;
470 }
471 return p;
472 }
473 static bool IsWhiteSpace( char p ) {
Jerome Martinez242c3ea2013-01-06 12:20:04 +0100474 return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200476
477 inline static bool IsNameStartChar( unsigned char ch ) {
478 return ( ( ch < 128 ) ? isalpha( ch ) : 1 )
479 || ch == ':'
480 || ch == '_';
481 }
482
483 inline static bool IsNameChar( unsigned char ch ) {
484 return IsNameStartChar( ch )
485 || isdigit( ch )
486 || ch == '.'
487 || ch == '-';
488 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800489
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
491 int n = 0;
492 if ( p == q ) {
493 return true;
494 }
495 while( *p && *q && *p == *q && n<nChar ) {
496 ++p;
497 ++q;
498 ++n;
499 }
500 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
501 return true;
502 }
503 return false;
504 }
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 inline static int IsUTF8Continuation( const char p ) {
507 return p & 0x80;
508 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800509
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 static const char* ReadBOM( const char* p, bool* hasBOM );
511 // p is the starting location,
512 // the UTF-8 value of the entity will be placed in value, and length filled in.
513 static const char* GetCharacterRef( const char* p, char* value, int* length );
514 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason21be8822012-07-15 17:27:22 -0700515
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 // converts primitive types to strings
517 static void ToStr( int v, char* buffer, int bufferSize );
518 static void ToStr( unsigned v, char* buffer, int bufferSize );
519 static void ToStr( bool v, char* buffer, int bufferSize );
520 static void ToStr( float v, char* buffer, int bufferSize );
521 static void ToStr( double v, char* buffer, int bufferSize );
Lee Thomason21be8822012-07-15 17:27:22 -0700522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 // converts strings to primitive types
524 static bool ToInt( const char* str, int* value );
525 static bool ToUnsigned( const char* str, unsigned* value );
526 static bool ToBool( const char* str, bool* value );
527 static bool ToFloat( const char* str, float* value );
528 static bool ToDouble( const char* str, double* value );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800529};
530
Lee Thomason5cae8972012-01-24 18:03:07 -0800531
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800532/** XMLNode is a base class for every object that is in the
533 XML Document Object Model (DOM), except XMLAttributes.
534 Nodes have siblings, a parent, and children which can
535 be navigated. A node is always in a XMLDocument.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700536 The type of a XMLNode can be queried, and it can
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800537 be cast to its more defined type.
538
Thomas Roß08bdf502012-05-12 14:21:23 +0200539 A XMLDocument allocates memory for all its Nodes.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800540 When the XMLDocument gets deleted, all its Nodes
541 will also be deleted.
542
543 @verbatim
544 A Document can contain: Element (container or leaf)
545 Comment (leaf)
546 Unknown (leaf)
547 Declaration( leaf )
548
549 An Element can contain: Element (container or leaf)
550 Text (leaf)
551 Attributes (not on tree)
552 Comment (leaf)
553 Unknown (leaf)
554
555 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800556*/
Lee Thomasond1983222012-02-06 08:41:24 -0800557class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 friend class XMLDocument;
560 friend class XMLElement;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 /// Get the XMLDocument that owns this XMLNode.
564 const XMLDocument* GetDocument() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700565 return _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 }
567 /// Get the XMLDocument that owns this XMLNode.
568 XMLDocument* GetDocument() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 return _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571
Lee Thomason2fa81722012-11-09 12:37:46 -0800572 /// Safely cast to an Element, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 virtual XMLElement* ToElement() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100574 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800576 /// Safely cast to Text, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 virtual XMLText* ToText() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100578 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800580 /// Safely cast to a Comment, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 virtual XMLComment* ToComment() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100582 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800584 /// Safely cast to a Document, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 virtual XMLDocument* ToDocument() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100586 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700587 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800588 /// Safely cast to a Declaration, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 virtual XMLDeclaration* ToDeclaration() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100590 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800592 /// Safely cast to an Unknown, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 virtual XMLUnknown* ToUnknown() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100594 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 virtual const XMLElement* ToElement() const {
598 return 0;
599 }
600 virtual const XMLText* ToText() const {
601 return 0;
602 }
603 virtual const XMLComment* ToComment() const {
604 return 0;
605 }
606 virtual const XMLDocument* ToDocument() const {
607 return 0;
608 }
609 virtual const XMLDeclaration* ToDeclaration() const {
610 return 0;
611 }
612 virtual const XMLUnknown* ToUnknown() const {
613 return 0;
614 }
Lee Thomason751da522012-02-10 08:50:51 -0800615
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 /** The meaning of 'value' changes for the specific type.
617 @verbatim
618 Document: empty
619 Element: name of the element
620 Comment: the comment text
621 Unknown: the tag contents
622 Text: the text string
623 @endverbatim
624 */
625 const char* Value() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700626 return _value.GetStr();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100628
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 /** Set the Value of an XML node.
630 @sa Value()
631 */
632 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800633
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 /// Get the parent of this node on the DOM.
635 const XMLNode* Parent() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 return _parent;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100638
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 XMLNode* Parent() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 return _parent;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason751da522012-02-10 08:50:51 -0800642
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 /// Returns true if this node has no children.
644 bool NoChildren() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 return !_firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 }
Lee Thomason751da522012-02-10 08:50:51 -0800647
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 /// Get the first child node, or null if none exists.
649 const XMLNode* FirstChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 return _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100652
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 XMLNode* FirstChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 return _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100656
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 /** Get the first child element, or optionally the first child
658 element with the specified name.
659 */
660 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700661
662 XMLElement* FirstChildElement( const char* value=0 ) {
663 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value ));
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 }
Lee Thomason3f57d272012-01-11 15:30:03 -0800665
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 /// Get the last child node, or null if none exists.
667 const XMLNode* LastChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 return _lastChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 XMLNode* LastChild() {
672 return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() );
673 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800674
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 /** Get the last child element or optionally the last child
676 element with the specified name.
677 */
678 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700679
680 XMLElement* LastChildElement( const char* value=0 ) {
681 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700683
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 /// Get the previous (left) sibling node of this node.
685 const XMLNode* PreviousSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 return _prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700688
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 XMLNode* PreviousSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 return _prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800692
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
694 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason624d43f2012-10-12 10:58:48 -0700695
696 XMLElement* PreviousSiblingElement( const char* value=0 ) {
697 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700699
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 /// Get the next (right) sibling node of this node.
701 const XMLNode* NextSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700704
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 XMLNode* NextSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700708
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
710 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700711
712 XMLElement* NextSiblingElement( const char* value=0 ) {
713 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800715
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 /**
717 Add a child node as the last (right) child.
718 */
719 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800720
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 XMLNode* LinkEndChild( XMLNode* addThis ) {
722 return InsertEndChild( addThis );
723 }
724 /**
725 Add a child node as the first (left) child.
726 */
727 XMLNode* InsertFirstChild( XMLNode* addThis );
728 /**
729 Add a node after the specified child node.
730 */
731 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700732
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 /**
734 Delete all the children of this node.
735 */
736 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800737
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 /**
739 Delete a child of this node.
740 */
741 void DeleteChild( XMLNode* node );
Lee Thomason56bdd022012-02-09 18:16:58 -0800742
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 /**
744 Make a copy of this node, but not its children.
745 You may pass in a Document pointer that will be
746 the owner of the new Node. If the 'document' is
747 null, then the node returned will be allocated
748 from the current Document. (this->GetDocument())
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800749
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 Note: if called on a XMLDocument, this will return null.
751 */
752 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800753
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 /**
755 Test if 2 nodes are the same, but don't test children.
756 The 2 nodes do not need to be in the same Document.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800757
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 Note: if called on a XMLDocument, this will return false.
759 */
760 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800761
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the
763 XML tree will be conditionally visited and the host will be called back
764 via the TiXmlVisitor interface.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800765
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
767 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
768 interface versus any other.)
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800769
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 The interface has been based on ideas from:
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800771
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 - http://www.saxproject.org/
773 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800774
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 Which are both good references for "visiting".
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800776
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 An example of using Accept():
778 @verbatim
779 TiXmlPrinter printer;
780 tinyxmlDoc.Accept( &printer );
781 const char* xmlcstr = printer.CStr();
782 @endverbatim
783 */
784 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800785
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // internal
787 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800788
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800789protected:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 XMLNode( XMLDocument* );
791 virtual ~XMLNode();
792 XMLNode( const XMLNode& ); // not supported
793 XMLNode& operator=( const XMLNode& ); // not supported
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700794
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 XMLDocument* _document;
796 XMLNode* _parent;
797 mutable StrPair _value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800798
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 XMLNode* _firstChild;
800 XMLNode* _lastChild;
Lee Thomason3f57d272012-01-11 15:30:03 -0800801
Lee Thomason624d43f2012-10-12 10:58:48 -0700802 XMLNode* _prev;
803 XMLNode* _next;
Lee Thomason3f57d272012-01-11 15:30:03 -0800804
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800805private:
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 MemPool* _memPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800808};
809
810
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800811/** XML text.
812
813 Note that a text node can have child element nodes, for example:
814 @verbatim
815 <root>This is <b>bold</b></root>
816 @endverbatim
817
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700818 A text node can have 2 ways to output the next. "normal" output
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800819 and CDATA. It will default to the mode it was parsed from the XML file and
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700820 you generally want to leave it alone, but you can change the output mode with
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800821 SetCDATA() and query it with CDATA().
822*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800823class XMLText : public XMLNode
824{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 friend class XMLBase;
826 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800827public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800829
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 virtual XMLText* ToText() {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return this;
832 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700833 virtual const XMLText* ToText() const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 return this;
835 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800836
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 /// Declare whether this should be CDATA or standard text.
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 void SetCData( bool isCData ) {
839 _isCData = isCData;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
841 /// Returns true if this is a CDATA text element.
842 bool CData() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 return _isCData;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800845
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 char* ParseDeep( char*, StrPair* endTag );
847 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
848 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800849
Lee Thomason5492a1c2012-01-23 15:32:10 -0800850protected:
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 virtual ~XMLText() {}
853 XMLText( const XMLText& ); // not supported
854 XMLText& operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800855
856private:
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 bool _isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800858};
859
860
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800861/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800862class XMLComment : public XMLNode
863{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800865public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 virtual XMLComment* ToComment() {
867 return this;
868 }
869 virtual const XMLComment* ToComment() const {
870 return this;
871 }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800872
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800874
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 char* ParseDeep( char*, StrPair* endTag );
876 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
877 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800878
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800879protected:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 XMLComment( XMLDocument* doc );
881 virtual ~XMLComment();
882 XMLComment( const XMLComment& ); // not supported
883 XMLComment& operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800884
Lee Thomason3f57d272012-01-11 15:30:03 -0800885private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800886};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800887
888
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800889/** In correct XML the declaration is the first entry in the file.
890 @verbatim
891 <?xml version="1.0" standalone="yes"?>
892 @endverbatim
893
894 TinyXML2 will happily read or write files without a declaration,
895 however.
896
897 The text of the declaration isn't interpreted. It is parsed
898 and written as a string.
899*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800900class XMLDeclaration : public XMLNode
901{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 friend class XMLDocument;
Lee Thomason50f97b22012-02-11 16:33:40 -0800903public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 virtual XMLDeclaration* ToDeclaration() {
905 return this;
906 }
907 virtual const XMLDeclaration* ToDeclaration() const {
908 return this;
909 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800910
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800912
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 char* ParseDeep( char*, StrPair* endTag );
914 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
915 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800916
917protected:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 XMLDeclaration( XMLDocument* doc );
919 virtual ~XMLDeclaration();
920 XMLDeclaration( const XMLDeclaration& ); // not supported
921 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800922};
923
924
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800925/** Any tag that tinyXml doesn't recognize is saved as an
926 unknown. It is a tag of text, but should not be modified.
927 It will be written back to the XML, unchanged, when the file
928 is saved.
929
930 DTD tags get thrown into TiXmlUnknowns.
931*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800932class XMLUnknown : public XMLNode
933{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 friend class XMLDocument;
Lee Thomason50f97b22012-02-11 16:33:40 -0800935public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 virtual XMLUnknown* ToUnknown() {
937 return this;
938 }
939 virtual const XMLUnknown* ToUnknown() const {
940 return this;
941 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800942
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800944
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 char* ParseDeep( char*, StrPair* endTag );
946 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
947 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800948
949protected:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 XMLUnknown( XMLDocument* doc );
951 virtual ~XMLUnknown();
952 XMLUnknown( const XMLUnknown& ); // not supported
953 XMLUnknown& operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800954};
955
956
Lee Thomason2fa81722012-11-09 12:37:46 -0800957enum XMLError {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 XML_NO_ERROR = 0,
959 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800960
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 XML_NO_ATTRIBUTE,
962 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800963
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 XML_ERROR_FILE_NOT_FOUND,
965 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
966 XML_ERROR_FILE_READ_ERROR,
967 XML_ERROR_ELEMENT_MISMATCH,
968 XML_ERROR_PARSING_ELEMENT,
969 XML_ERROR_PARSING_ATTRIBUTE,
970 XML_ERROR_IDENTIFYING_TAG,
971 XML_ERROR_PARSING_TEXT,
972 XML_ERROR_PARSING_CDATA,
973 XML_ERROR_PARSING_COMMENT,
974 XML_ERROR_PARSING_DECLARATION,
975 XML_ERROR_PARSING_UNKNOWN,
976 XML_ERROR_EMPTY_DOCUMENT,
977 XML_ERROR_MISMATCHED_ELEMENT,
978 XML_ERROR_PARSING,
Lee Thomason21be8822012-07-15 17:27:22 -0700979
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 XML_CAN_NOT_CONVERT_TEXT,
981 XML_NO_TEXT_NODE
Lee Thomason1ff38e02012-02-14 18:18:16 -0800982};
983
984
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800985/** An attribute is a name-value pair. Elements have an arbitrary
986 number of attributes, each with a unique name.
987
988 @note The attributes are not XMLNodes. You may only query the
989 Next() attribute in a list.
990*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800991class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 friend class XMLElement;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800994public:
Lee Thomason2fa81722012-11-09 12:37:46 -0800995 /// The name of the attribute.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 const char* Name() const {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100997 return _name.GetStr();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800999 /// The value of the attribute.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 const char* Value() const {
MortenMacFly4ee49f12013-01-14 20:03:14 +01001001 return _value.GetStr();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 }
Lee Thomason2fa81722012-11-09 12:37:46 -08001003 /// The next attribute in the list.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 const XMLAttribute* Next() const {
MortenMacFly4ee49f12013-01-14 20:03:14 +01001005 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001007
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 /** IntAttribute interprets the attribute as an integer, and returns the value.
1009 If the value isn't an integer, 0 will be returned. There is no error checking;
1010 use QueryIntAttribute() if you need error checking.
1011 */
1012 int IntValue() const {
1013 int i=0;
1014 QueryIntValue( &i );
1015 return i;
1016 }
1017 /// Query as an unsigned integer. See IntAttribute()
1018 unsigned UnsignedValue() const {
1019 unsigned i=0;
1020 QueryUnsignedValue( &i );
1021 return i;
1022 }
1023 /// Query as a boolean. See IntAttribute()
1024 bool BoolValue() const {
1025 bool b=false;
1026 QueryBoolValue( &b );
1027 return b;
1028 }
1029 /// Query as a double. See IntAttribute()
1030 double DoubleValue() const {
1031 double d=0;
1032 QueryDoubleValue( &d );
1033 return d;
1034 }
1035 /// Query as a float. See IntAttribute()
1036 float FloatValue() const {
1037 float f=0;
1038 QueryFloatValue( &f );
1039 return f;
1040 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001041
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
1043 in the provided paremeter. The function will return XML_NO_ERROR on success,
1044 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1045 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001046 XMLError QueryIntValue( int* value ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 /// See QueryIntAttribute
Lee Thomason2fa81722012-11-09 12:37:46 -08001048 XMLError QueryUnsignedValue( unsigned int* value ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 /// See QueryIntAttribute
Lee Thomason2fa81722012-11-09 12:37:46 -08001050 XMLError QueryBoolValue( bool* value ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 /// See QueryIntAttribute
Lee Thomason2fa81722012-11-09 12:37:46 -08001052 XMLError QueryDoubleValue( double* value ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 /// See QueryIntAttribute
Lee Thomason2fa81722012-11-09 12:37:46 -08001054 XMLError QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -08001055
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 /// Set the attribute to a string value.
1057 void SetAttribute( const char* value );
1058 /// Set the attribute to value.
1059 void SetAttribute( int value );
1060 /// Set the attribute to value.
1061 void SetAttribute( unsigned value );
1062 /// Set the attribute to value.
1063 void SetAttribute( bool value );
1064 /// Set the attribute to value.
1065 void SetAttribute( double value );
1066 /// Set the attribute to value.
1067 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -08001068
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001069private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001071
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 XMLAttribute() : _next( 0 ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 virtual ~XMLAttribute() {}
Lee Thomason624d43f2012-10-12 10:58:48 -07001074
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 XMLAttribute( const XMLAttribute& ); // not supported
1076 void operator=( const XMLAttribute& ); // not supported
1077 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -08001078
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001080
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 mutable StrPair _name;
1082 mutable StrPair _value;
1083 XMLAttribute* _next;
1084 MemPool* _memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001085};
1086
1087
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001088/** The element is a container class. It has a value, the element name,
1089 and can contain other elements, text, comments, and unknowns.
1090 Elements also contain an arbitrary number of attributes.
1091*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001092class XMLElement : public XMLNode
1093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 friend class XMLBase;
1095 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001096public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 /// Get the name of an element (which is the Value() of the node.)
1098 const char* Name() const {
1099 return Value();
1100 }
1101 /// Set the name of the element.
1102 void SetName( const char* str, bool staticMem=false ) {
1103 SetValue( str, staticMem );
1104 }
Lee Thomason2c85a712012-01-31 08:24:24 -08001105
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 virtual XMLElement* ToElement() {
1107 return this;
1108 }
1109 virtual const XMLElement* ToElement() const {
1110 return this;
1111 }
1112 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001113
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 /** Given an attribute name, Attribute() returns the value
1115 for the attribute of that name, or null if none
1116 exists. For example:
Lee Thomason92258152012-03-24 13:05:39 -07001117
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 @verbatim
1119 const char* value = ele->Attribute( "foo" );
1120 @endverbatim
Lee Thomason92258152012-03-24 13:05:39 -07001121
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 The 'value' parameter is normally null. However, if specified,
1123 the attribute will only be returned if the 'name' and 'value'
1124 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001125
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 @verbatim
1127 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1128 @endverbatim
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001129
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 rather than:
1131 @verbatim
1132 if ( ele->Attribute( "foo" ) ) {
1133 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1134 }
1135 @endverbatim
1136 */
1137 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -08001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 /** Given an attribute name, IntAttribute() returns the value
1140 of the attribute interpreted as an integer. 0 will be
1141 returned if there is an error. For a method with error
1142 checking, see QueryIntAttribute()
1143 */
1144 int IntAttribute( const char* name ) const {
1145 int i=0;
1146 QueryIntAttribute( name, &i );
1147 return i;
1148 }
1149 /// See IntAttribute()
1150 unsigned UnsignedAttribute( const char* name ) const {
1151 unsigned i=0;
1152 QueryUnsignedAttribute( name, &i );
1153 return i;
1154 }
1155 /// See IntAttribute()
1156 bool BoolAttribute( const char* name ) const {
1157 bool b=false;
1158 QueryBoolAttribute( name, &b );
1159 return b;
1160 }
1161 /// See IntAttribute()
1162 double DoubleAttribute( const char* name ) const {
1163 double d=0;
1164 QueryDoubleAttribute( name, &d );
1165 return d;
1166 }
1167 /// See IntAttribute()
1168 float FloatAttribute( const char* name ) const {
1169 float f=0;
1170 QueryFloatAttribute( name, &f );
1171 return f;
1172 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001173
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 /** Given an attribute name, QueryIntAttribute() returns
1175 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1176 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1177 doesn't exist. If successful, the result of the conversion
1178 will be written to 'value'. If not successful, nothing will
1179 be written to 'value'. This allows you to provide default
1180 value:
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001181
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 @verbatim
1183 int value = 10;
1184 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1185 @endverbatim
1186 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001187 XMLError QueryIntAttribute( const char* name, int* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 const XMLAttribute* a = FindAttribute( name );
1189 if ( !a ) {
1190 return XML_NO_ATTRIBUTE;
1191 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001192 return a->QueryIntValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 }
1194 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001195 XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 const XMLAttribute* a = FindAttribute( name );
1197 if ( !a ) {
1198 return XML_NO_ATTRIBUTE;
1199 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001200 return a->QueryUnsignedValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 }
1202 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001203 XMLError QueryBoolAttribute( const char* name, bool* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 const XMLAttribute* a = FindAttribute( name );
1205 if ( !a ) {
1206 return XML_NO_ATTRIBUTE;
1207 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 return a->QueryBoolValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 }
1210 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001211 XMLError QueryDoubleAttribute( const char* name, double* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 const XMLAttribute* a = FindAttribute( name );
1213 if ( !a ) {
1214 return XML_NO_ATTRIBUTE;
1215 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 return a->QueryDoubleValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
1218 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001219 XMLError QueryFloatAttribute( const char* name, float* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 const XMLAttribute* a = FindAttribute( name );
1221 if ( !a ) {
1222 return XML_NO_ATTRIBUTE;
1223 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 return a->QueryFloatValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001226
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 void SetAttribute( const char* name, const char* value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 }
1232 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 void SetAttribute( const char* name, int value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001235 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 }
1237 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 void SetAttribute( const char* name, unsigned value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 }
1242 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 void SetAttribute( const char* name, bool value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001245 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 }
1247 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 void SetAttribute( const char* name, double value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001252
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 /**
1254 Delete an attribute.
1255 */
1256 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -08001257
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 /// Return the first attribute in the list.
1259 const XMLAttribute* FirstAttribute() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 return _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 }
1262 /// Query a specific attribute in the list.
1263 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -08001264
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 /** Convenience function for easy access to the text inside an element. Although easy
1266 and concise, GetText() is limited compared to getting the TiXmlText child
1267 and accessing it directly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001268
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 If the first child of 'this' is a TiXmlText, the GetText()
1270 returns the character string of the Text node, else null is returned.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001271
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 This is a convenient method for getting the text of simple contained text:
1273 @verbatim
1274 <foo>This is text</foo>
1275 const char* str = fooElement->GetText();
1276 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001277
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 'str' will be a pointer to "This is text".
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001279
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 Note that this function can be misleading. If the element foo was created from
1281 this XML:
1282 @verbatim
1283 <foo><b>This is text</b></foo>
1284 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001285
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 then the value of str would be null. The first child node isn't a text node, it is
1287 another element. From this XML:
1288 @verbatim
1289 <foo>This is <b>text</b></foo>
1290 @endverbatim
1291 GetText() will return "This is ".
1292 */
1293 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -08001294
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 /**
1296 Convenience method to query the value of a child text node. This is probably best
1297 shown by example. Given you have a document is this form:
1298 @verbatim
1299 <point>
1300 <x>1</x>
1301 <y>1.4</y>
1302 </point>
1303 @endverbatim
Lee Thomason21be8822012-07-15 17:27:22 -07001304
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 The QueryIntText() and similar functions provide a safe and easier way to get to the
1306 "value" of x and y.
Lee Thomason21be8822012-07-15 17:27:22 -07001307
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 @verbatim
1309 int x = 0;
1310 float y = 0; // types of x and y are contrived for example
1311 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1312 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1313 xElement->QueryIntText( &x );
1314 yElement->QueryFloatText( &y );
1315 @endverbatim
Lee Thomason21be8822012-07-15 17:27:22 -07001316
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1318 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001319
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 */
MortenMacFly4ee49f12013-01-14 20:03:14 +01001321 XMLError QueryIntText( int* ival ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001323 XMLError QueryUnsignedText( unsigned* uval ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001325 XMLError QueryBoolText( bool* bval ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001327 XMLError QueryDoubleText( double* dval ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001329 XMLError QueryFloatText( float* fval ) const;
Lee Thomason21be8822012-07-15 17:27:22 -07001330
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 // internal:
1332 enum {
1333 OPEN, // <foo>
1334 CLOSED, // <foo/>
1335 CLOSING // </foo>
1336 };
1337 int ClosingType() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001338 return _closingType;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 }
1340 char* ParseDeep( char* p, StrPair* endTag );
1341 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1342 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001343
Lee Thomason50adb4c2012-02-13 15:07:09 -08001344private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 XMLElement( XMLDocument* doc );
1346 virtual ~XMLElement();
1347 XMLElement( const XMLElement& ); // not supported
1348 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001349
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 XMLAttribute* FindAttribute( const char* name );
1351 XMLAttribute* FindOrCreateAttribute( const char* name );
1352 //void LinkAttribute( XMLAttribute* attrib );
1353 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -08001354
Lee Thomason624d43f2012-10-12 10:58:48 -07001355 int _closingType;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 // The attribute list is ordered; there is no 'lastAttribute'
1357 // because the list needs to be scanned for dupes before adding
1358 // a new attribute.
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 XMLAttribute* _rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001360};
1361
1362
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001363enum Whitespace {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 PRESERVE_WHITESPACE,
1365 COLLAPSE_WHITESPACE
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001366};
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001367
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001368
1369/** A Document binds together all the functionality.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001370 It can be saved, loaded, and printed to the screen.
1371 All Nodes are connected and allocated to a Document.
1372 If the Document is deleted, all its Nodes are also deleted.
1373*/
Lee Thomason67d61312012-01-24 16:01:51 -08001374class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001377public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 /// constructor
1379 XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
1380 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001381
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 virtual XMLDocument* ToDocument() {
1383 return this;
1384 }
1385 virtual const XMLDocument* ToDocument() const {
1386 return this;
1387 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001388
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 /**
1390 Parse an XML file from a character string.
1391 Returns XML_NO_ERROR (0) on success, or
1392 an errorID.
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001393
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 You may optionally pass in the 'nBytes', which is
1395 the number of bytes which will be parsed. If not
1396 specified, TinyXML will assume 'xml' points to a
1397 null terminated string.
1398 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001399 XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001400
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 /**
1402 Load an XML file from disk.
1403 Returns XML_NO_ERROR (0) on success, or
1404 an errorID.
1405 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001406 XMLError LoadFile( const char* filename );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001407
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 /**
1409 Load an XML file from disk. You are responsible
1410 for providing and closing the FILE*.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001411
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 Returns XML_NO_ERROR (0) on success, or
1413 an errorID.
1414 */
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001415 XMLError LoadFile( FILE* );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001416
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 /**
1418 Save the XML file to disk.
1419 Returns XML_NO_ERROR (0) on success, or
1420 an errorID.
1421 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001422 XMLError SaveFile( const char* filename, bool compact = false );
Lee Thomasond11cd162012-04-12 08:35:36 -07001423
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 /**
1425 Save the XML file to disk. You are responsible
1426 for providing and closing the FILE*.
Ken Miller81da1fb2012-04-09 23:32:26 -05001427
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 Returns XML_NO_ERROR (0) on success, or
1429 an errorID.
1430 */
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001431 XMLError SaveFile( FILE* fp, bool compact = false );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001432
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 bool ProcessEntities() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 return _processEntities;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 }
1436 Whitespace WhitespaceMode() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 return _whitespace;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001439
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 /**
1441 Returns true if this document has a leading Byte Order Mark of UTF8.
1442 */
1443 bool HasBOM() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 return _writeBOM;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 }
1446 /** Sets whether to write the BOM when writing the file.
1447 */
1448 void SetBOM( bool useBOM ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 _writeBOM = useBOM;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001451
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 /** Return the root element of DOM. Equivalent to FirstChildElement().
1453 To get the first node, use FirstChild().
1454 */
1455 XMLElement* RootElement() {
1456 return FirstChildElement();
1457 }
1458 const XMLElement* RootElement() const {
1459 return FirstChildElement();
1460 }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001461
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 /** Print the Document. If the Printer is not provided, it will
1463 print to stdout. If you provide Printer, this can print to a file:
1464 @verbatim
1465 XMLPrinter printer( fp );
1466 doc.Print( &printer );
1467 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001468
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 Or you can use a printer to print to memory:
1470 @verbatim
1471 XMLPrinter printer;
1472 doc->Print( &printer );
1473 // printer.CStr() has a const char* to the XML
1474 @endverbatim
1475 */
1476 void Print( XMLPrinter* streamer=0 );
1477 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001478
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 /**
1480 Create a new Element associated with
1481 this Document. The memory for the Element
1482 is managed by the Document.
1483 */
1484 XMLElement* NewElement( const char* name );
1485 /**
1486 Create a new Comment associated with
1487 this Document. The memory for the Comment
1488 is managed by the Document.
1489 */
1490 XMLComment* NewComment( const char* comment );
1491 /**
1492 Create a new Text associated with
1493 this Document. The memory for the Text
1494 is managed by the Document.
1495 */
1496 XMLText* NewText( const char* text );
1497 /**
1498 Create a new Declaration associated with
1499 this Document. The memory for the object
1500 is managed by the Document.
Lee Thomasonf68c4382012-04-28 14:37:11 -07001501
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 If the 'text' param is null, the standard
1503 declaration is used.:
1504 @verbatim
1505 <?xml version="1.0" encoding="UTF-8"?>
1506 @endverbatim
1507 */
1508 XMLDeclaration* NewDeclaration( const char* text=0 );
1509 /**
1510 Create a new Unknown associated with
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 this Document. The memory forthe object
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 is managed by the Document.
1513 */
1514 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001515
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 /**
1517 Delete a node associated with this document.
1518 It will be unlinked from the DOM.
1519 */
1520 void DeleteNode( XMLNode* node ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001521 node->_parent->DeleteChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001523
Lee Thomason2fa81722012-11-09 12:37:46 -08001524 void SetError( XMLError error, const char* str1, const char* str2 );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001525
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 /// Return true if there was an error parsing the document.
1527 bool Error() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001528 return _errorID != XML_NO_ERROR;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 }
1530 /// Return the errorID.
Lee Thomason2fa81722012-11-09 12:37:46 -08001531 XMLError ErrorID() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001532 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 }
1534 /// Return a possibly helpful diagnostic location or string.
1535 const char* GetErrorStr1() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 return _errorStr1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 }
1538 /// Return a possibly helpful secondary diagnostic location or string.
1539 const char* GetErrorStr2() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 return _errorStr2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 }
1542 /// If there is an error, print it to stdout.
1543 void PrintError() const;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001544
1545 /// Clear the document, resetting it to the initial state.
1546 void Clear();
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 // internal
1549 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001550
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
1552 return 0;
1553 }
1554 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
1555 return false;
1556 }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001557
Lee Thomason3f57d272012-01-11 15:30:03 -08001558private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 XMLDocument( const XMLDocument& ); // not supported
1560 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001561
Lee Thomason2fa81722012-11-09 12:37:46 -08001562 bool _writeBOM;
1563 bool _processEntities;
1564 XMLError _errorID;
1565 Whitespace _whitespace;
Lee Thomason624d43f2012-10-12 10:58:48 -07001566 const char* _errorStr1;
1567 const char* _errorStr2;
Lee Thomason2fa81722012-11-09 12:37:46 -08001568 char* _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001569
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 MemPoolT< sizeof(XMLElement) > _elementPool;
1571 MemPoolT< sizeof(XMLAttribute) > _attributePool;
1572 MemPoolT< sizeof(XMLText) > _textPool;
1573 MemPoolT< sizeof(XMLComment) > _commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001574};
1575
Lee Thomason7c913cd2012-01-26 18:32:34 -08001576
Lee Thomason3ffdd392012-03-28 17:27:55 -07001577/**
1578 A XMLHandle is a class that wraps a node pointer with null checks; this is
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001579 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
Lee Thomason3ffdd392012-03-28 17:27:55 -07001580 DOM structure. It is a separate utility class.
1581
1582 Take an example:
1583 @verbatim
1584 <Document>
1585 <Element attributeA = "valueA">
1586 <Child attributeB = "value1" />
1587 <Child attributeB = "value2" />
1588 </Element>
Thomas Roß08bdf502012-05-12 14:21:23 +02001589 </Document>
Lee Thomason3ffdd392012-03-28 17:27:55 -07001590 @endverbatim
1591
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001592 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
Lee Thomason3ffdd392012-03-28 17:27:55 -07001593 easy to write a *lot* of code that looks like:
1594
1595 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001596 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001597 if ( root )
1598 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001599 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001600 if ( element )
1601 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001602 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001603 if ( child )
1604 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001605 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001606 if ( child2 )
1607 {
1608 // Finally do something useful.
1609 @endverbatim
1610
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001611 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001612 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07001613 and correct to use:
1614
1615 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07001616 XMLHandle docHandle( &document );
1617 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07001618 if ( child2 )
1619 {
1620 // do something useful
1621 @endverbatim
1622
1623 Which is MUCH more concise and useful.
1624
1625 It is also safe to copy handles - internally they are nothing more than node pointers.
1626 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001627 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001628 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001629
1630 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001631*/
1632class XMLHandle
1633{
1634public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
Lee Thomason624d43f2012-10-12 10:58:48 -07001636 XMLHandle( XMLNode* node ) {
1637 _node = node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 }
1639 /// Create a handle from a node.
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 XMLHandle( XMLNode& node ) {
1641 _node = &node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 }
1643 /// Copy constructor
1644 XMLHandle( const XMLHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 }
1647 /// Assignment
1648 XMLHandle& operator=( const XMLHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 return *this;
1651 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001652
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 /// Get the first child of this handle.
1654 XMLHandle FirstChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 return XMLHandle( _node ? _node->FirstChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 }
1657 /// Get the first child element of this handle.
1658 XMLHandle FirstChildElement( const char* value=0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 }
1661 /// Get the last child of this handle.
1662 XMLHandle LastChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001663 return XMLHandle( _node ? _node->LastChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 }
1665 /// Get the last child element of this handle.
1666 XMLHandle LastChildElement( const char* _value=0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 }
1669 /// Get the previous sibling of this handle.
1670 XMLHandle PreviousSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 return XMLHandle( _node ? _node->PreviousSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 }
1673 /// Get the previous sibling element of this handle.
1674 XMLHandle PreviousSiblingElement( const char* _value=0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 }
1677 /// Get the next sibling of this handle.
1678 XMLHandle NextSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 return XMLHandle( _node ? _node->NextSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 }
1681 /// Get the next sibling element of this handle.
1682 XMLHandle NextSiblingElement( const char* _value=0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001685
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 /// Safe cast to XMLNode. This can return null.
1687 XMLNode* ToNode() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 return _node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 }
1690 /// Safe cast to XMLElement. This can return null.
1691 XMLElement* ToElement() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 }
1694 /// Safe cast to XMLText. This can return null.
1695 XMLText* ToText() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 }
1698 /// Safe cast to XMLUnknown. This can return null.
1699 XMLUnknown* ToUnknown() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 }
1702 /// Safe cast to XMLDeclaration. This can return null.
1703 XMLDeclaration* ToDeclaration() {
Lee Thomason624d43f2012-10-12 10:58:48 -07001704 return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001706
1707private:
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 XMLNode* _node;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001709};
1710
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001711
1712/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001713 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1714 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07001715*/
1716class XMLConstHandle
1717{
1718public:
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 XMLConstHandle( const XMLNode* node ) {
1720 _node = node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 XMLConstHandle( const XMLNode& node ) {
1723 _node = &node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
1725 XMLConstHandle( const XMLConstHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 }
Lee Thomason8b899812012-04-04 15:58:16 -07001728
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 XMLConstHandle& operator=( const XMLConstHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 return *this;
1732 }
Lee Thomason8b899812012-04-04 15:58:16 -07001733
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 const XMLConstHandle FirstChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 return XMLConstHandle( _node ? _node->FirstChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 }
1737 const XMLConstHandle FirstChildElement( const char* value=0 ) const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 }
1740 const XMLConstHandle LastChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 return XMLConstHandle( _node ? _node->LastChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 }
1743 const XMLConstHandle LastChildElement( const char* _value=0 ) const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 }
1746 const XMLConstHandle PreviousSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 }
1749 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 }
1752 const XMLConstHandle NextSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 return XMLConstHandle( _node ? _node->NextSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 }
Lee Thomason8b899812012-04-04 15:58:16 -07001758
1759
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 const XMLNode* ToNode() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 return _node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 }
1763 const XMLElement* ToElement() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 }
1766 const XMLText* ToText() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 }
1769 const XMLUnknown* ToUnknown() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 }
1772 const XMLDeclaration* ToDeclaration() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001775
Lee Thomason5cae8972012-01-24 18:03:07 -08001776private:
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 const XMLNode* _node;
Lee Thomason56bdd022012-02-09 18:16:58 -08001778};
Lee Thomason6f381b72012-03-02 12:59:39 -08001779
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001780
1781/**
1782 Printing functionality. The XMLPrinter gives you more
1783 options than the XMLDocument::Print() method.
1784
1785 It can:
1786 -# Print to memory.
Thomas Roß08bdf502012-05-12 14:21:23 +02001787 -# Print to a file you provide.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001788 -# Print XML without a XMLDocument.
1789
1790 Print to Memory
1791
1792 @verbatim
1793 XMLPrinter printer;
1794 doc->Print( &printer );
Thomas Roß08bdf502012-05-12 14:21:23 +02001795 SomeFunction( printer.CStr() );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001796 @endverbatim
1797
1798 Print to a File
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001799
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001800 You provide the file pointer.
1801 @verbatim
1802 XMLPrinter printer( fp );
1803 doc.Print( &printer );
1804 @endverbatim
1805
1806 Print without a XMLDocument
1807
1808 When loading, an XML parser is very useful. However, sometimes
1809 when saving, it just gets in the way. The code is often set up
1810 for streaming, and constructing the DOM is just overhead.
1811
1812 The Printer supports the streaming case. The following code
1813 prints out a trivially simple XML file without ever creating
1814 an XML document.
1815
1816 @verbatim
1817 XMLPrinter printer( fp );
1818 printer.OpenElement( "foo" );
1819 printer.PushAttribute( "foo", "bar" );
1820 printer.CloseElement();
1821 @endverbatim
1822*/
1823class XMLPrinter : public XMLVisitor
1824{
1825public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 /** Construct the printer. If the FILE* is specified,
1827 this will print to the FILE. Else it will print
1828 to memory, and the result is available in CStr().
1829 If 'compact' is set to true, then output is created
1830 with only required whitespace and newlines.
1831 */
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001832 XMLPrinter( FILE* file=0, bool compact = false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 ~XMLPrinter() {}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001834
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 /** If streaming, write the BOM and declaration. */
1836 void PushHeader( bool writeBOM, bool writeDeclaration );
1837 /** If streaming, start writing an element.
1838 The element must be closed with CloseElement()
1839 */
1840 void OpenElement( const char* name );
1841 /// If streaming, add an attribute to an open element.
1842 void PushAttribute( const char* name, const char* value );
1843 void PushAttribute( const char* name, int value );
1844 void PushAttribute( const char* name, unsigned value );
1845 void PushAttribute( const char* name, bool value );
1846 void PushAttribute( const char* name, double value );
1847 /// If streaming, close the Element.
1848 void CloseElement();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001849
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 /// Add a text node.
1851 void PushText( const char* text, bool cdata=false );
1852 /// Add a text node from an integer.
1853 void PushText( int value );
1854 /// Add a text node from an unsigned.
1855 void PushText( unsigned value );
1856 /// Add a text node from a bool.
1857 void PushText( bool value );
1858 /// Add a text node from a float.
1859 void PushText( float value );
1860 /// Add a text node from a double.
1861 void PushText( double value );
Lee Thomason21be8822012-07-15 17:27:22 -07001862
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 /// Add a comment
1864 void PushComment( const char* comment );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001865
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 void PushDeclaration( const char* value );
1867 void PushUnknown( const char* value );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001868
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
1870 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
1871 return true;
1872 }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001873
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1875 virtual bool VisitExit( const XMLElement& element );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001876
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 virtual bool Visit( const XMLText& text );
1878 virtual bool Visit( const XMLComment& comment );
1879 virtual bool Visit( const XMLDeclaration& declaration );
1880 virtual bool Visit( const XMLUnknown& unknown );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001881
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 /**
1883 If in print to memory mode, return a pointer to
1884 the XML file in memory.
1885 */
1886 const char* CStr() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 return _buffer.Mem();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 }
1889 /**
1890 If in print to memory mode, return the size
1891 of the XML file in memory. (Note the size returned
1892 includes the terminating null.)
1893 */
1894 int CStrSize() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 return _buffer.Size();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001897
1898private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 void SealElement();
1900 void PrintSpace( int depth );
1901 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
1902 void Print( const char* format, ... );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001903
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 bool _elementJustOpened;
1905 bool _firstElement;
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001906 FILE* _fp;
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 int _depth;
1908 int _textDepth;
1909 bool _processEntities;
1910 bool _compactMode;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001911
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 enum {
1913 ENTITY_RANGE = 64,
1914 BUF_SIZE = 200
1915 };
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 bool _entityFlag[ENTITY_RANGE];
1917 bool _restrictedEntityFlag[ENTITY_RANGE];
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001918
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 DynArray< const char*, 10 > _stack;
1920 DynArray< char, 20 > _buffer;
PKEuSe736f292012-07-16 03:27:55 -07001921#ifdef _MSC_VER
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 DynArray< char, 20 > _accumulator;
PKEuSe736f292012-07-16 03:27:55 -07001923#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001924};
1925
1926
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001927} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001928
1929
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001930#endif // TINYXML2_INCLUDED