/src/cppcheck/externals/tinyxml2/tinyxml2.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Original code by Lee Thomason (www.grinninglizard.com) |
3 | | |
4 | | This software is provided 'as-is', without any express or implied |
5 | | warranty. In no event will the authors be held liable for any |
6 | | damages arising from the use of this software. |
7 | | |
8 | | Permission is granted to anyone to use this software for any |
9 | | purpose, including commercial applications, and to alter it and |
10 | | redistribute it freely, subject to the following restrictions: |
11 | | |
12 | | 1. The origin of this software must not be misrepresented; you must |
13 | | not claim that you wrote the original software. If you use this |
14 | | software in a product, an acknowledgment in the product documentation |
15 | | would be appreciated but is not required. |
16 | | |
17 | | 2. Altered source versions must be plainly marked as such, and |
18 | | must not be misrepresented as being the original software. |
19 | | |
20 | | 3. This notice may not be removed or altered from any source |
21 | | distribution. |
22 | | */ |
23 | | |
24 | | #ifndef TINYXML2_INCLUDED |
25 | | #define TINYXML2_INCLUDED |
26 | | |
27 | | #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) |
28 | | # include <ctype.h> |
29 | | # include <limits.h> |
30 | | # include <stdio.h> |
31 | | # include <stdlib.h> |
32 | | # include <string.h> |
33 | | # if defined(__PS3__) |
34 | | # include <stddef.h> |
35 | | # endif |
36 | | #else |
37 | | # include <cctype> |
38 | | # include <climits> |
39 | | # include <cstdio> |
40 | | # include <cstdlib> |
41 | | # include <cstring> |
42 | | #endif |
43 | | #include <stdint.h> |
44 | | |
45 | | /* |
46 | | gcc: |
47 | | g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe |
48 | | |
49 | | Formatting, Artistic Style: |
50 | | AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h |
51 | | */ |
52 | | |
53 | | #if defined( _DEBUG ) || defined (__DEBUG__) |
54 | | # ifndef TINYXML2_DEBUG |
55 | | # define TINYXML2_DEBUG |
56 | | # endif |
57 | | #endif |
58 | | |
59 | | #ifdef _MSC_VER |
60 | | # pragma warning(push) |
61 | | # pragma warning(disable: 4251) |
62 | | #endif |
63 | | |
64 | | #ifdef _MSC_VER |
65 | | # ifdef TINYXML2_EXPORT |
66 | | # define TINYXML2_LIB __declspec(dllexport) |
67 | | # elif defined(TINYXML2_IMPORT) |
68 | | # define TINYXML2_LIB __declspec(dllimport) |
69 | | # else |
70 | | # define TINYXML2_LIB |
71 | | # endif |
72 | | #elif __GNUC__ >= 4 |
73 | | # define TINYXML2_LIB __attribute__((visibility("default"))) |
74 | | #else |
75 | | # define TINYXML2_LIB |
76 | | #endif |
77 | | |
78 | | |
79 | | #if !defined(TIXMLASSERT) |
80 | | #if defined(TINYXML2_DEBUG) |
81 | | # if defined(_MSC_VER) |
82 | | # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like |
83 | | # define TIXMLASSERT( x ) do { if ( !((void)0,(x))) { __debugbreak(); } } while(false) |
84 | | # elif defined (ANDROID_NDK) |
85 | | # include <android/log.h> |
86 | | # define TIXMLASSERT( x ) do { if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } } while(false) |
87 | | # else |
88 | | # include <assert.h> |
89 | | # define TIXMLASSERT assert |
90 | | # endif |
91 | | #else |
92 | 0 | # define TIXMLASSERT( x ) do {} while(false) |
93 | | #endif |
94 | | #endif |
95 | | |
96 | | /* Versioning, past 1.0.14: |
97 | | http://semver.org/ |
98 | | */ |
99 | | static const int TIXML2_MAJOR_VERSION = 10; |
100 | | static const int TIXML2_MINOR_VERSION = 0; |
101 | | static const int TIXML2_PATCH_VERSION = 0; |
102 | | |
103 | | #define TINYXML2_MAJOR_VERSION 10 |
104 | | #define TINYXML2_MINOR_VERSION 0 |
105 | | #define TINYXML2_PATCH_VERSION 0 |
106 | | |
107 | | // A fixed element depth limit is problematic. There needs to be a |
108 | | // limit to avoid a stack overflow. However, that limit varies per |
109 | | // system, and the capacity of the stack. On the other hand, it's a trivial |
110 | | // attack that can result from ill, malicious, or even correctly formed XML, |
111 | | // so there needs to be a limit in place. |
112 | | static const int TINYXML2_MAX_ELEMENT_DEPTH = 500; |
113 | | |
114 | | namespace tinyxml2 |
115 | | { |
116 | | class XMLDocument; |
117 | | class XMLElement; |
118 | | class XMLAttribute; |
119 | | class XMLComment; |
120 | | class XMLText; |
121 | | class XMLDeclaration; |
122 | | class XMLUnknown; |
123 | | class XMLPrinter; |
124 | | |
125 | | /* |
126 | | A class that wraps strings. Normally stores the start and end |
127 | | pointers into the XML file itself, and will apply normalization |
128 | | and entity translation if actually read. Can also store (and memory |
129 | | manage) a traditional char[] |
130 | | |
131 | | Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 |
132 | | */ |
133 | | class TINYXML2_LIB StrPair |
134 | | { |
135 | | public: |
136 | | enum Mode { |
137 | | NEEDS_ENTITY_PROCESSING = 0x01, |
138 | | NEEDS_NEWLINE_NORMALIZATION = 0x02, |
139 | | NEEDS_WHITESPACE_COLLAPSING = 0x04, |
140 | | |
141 | | TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, |
142 | | TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, |
143 | | ATTRIBUTE_NAME = 0, |
144 | | ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, |
145 | | ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, |
146 | | COMMENT = NEEDS_NEWLINE_NORMALIZATION |
147 | | }; |
148 | | |
149 | 0 | StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} |
150 | | ~StrPair(); |
151 | | |
152 | 0 | void Set( char* start, char* end, int flags ) { |
153 | 0 | TIXMLASSERT( start ); |
154 | 0 | TIXMLASSERT( end ); |
155 | 0 | Reset(); |
156 | 0 | _start = start; |
157 | 0 | _end = end; |
158 | 0 | _flags = flags | NEEDS_FLUSH; |
159 | 0 | } |
160 | | |
161 | | const char* GetStr(); |
162 | | |
163 | 0 | bool Empty() const { |
164 | 0 | return _start == _end; |
165 | 0 | } |
166 | | |
167 | 0 | void SetInternedStr( const char* str ) { |
168 | 0 | Reset(); |
169 | 0 | _start = const_cast<char*>(str); |
170 | 0 | } |
171 | | |
172 | | void SetStr( const char* str, int flags=0 ); |
173 | | |
174 | | char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); |
175 | | char* ParseName( char* in ); |
176 | | |
177 | | void TransferTo( StrPair* other ); |
178 | | void Reset(); |
179 | | |
180 | | private: |
181 | | void CollapseWhitespace(); |
182 | | |
183 | | enum { |
184 | | NEEDS_FLUSH = 0x100, |
185 | | NEEDS_DELETE = 0x200 |
186 | | }; |
187 | | |
188 | | int _flags; |
189 | | char* _start; |
190 | | char* _end; |
191 | | |
192 | | StrPair( const StrPair& other ); // not supported |
193 | | void operator=( const StrPair& other ); // not supported, use TransferTo() |
194 | | }; |
195 | | |
196 | | |
197 | | /* |
198 | | A dynamic array of Plain Old Data. Doesn't support constructors, etc. |
199 | | Has a small initial memory pool, so that low or no usage will not |
200 | | cause a call to new/delete |
201 | | */ |
202 | | template <class T, int INITIAL_SIZE> |
203 | | class DynArray |
204 | | { |
205 | | public: |
206 | | DynArray() : |
207 | 0 | _mem( _pool ), |
208 | 0 | _allocated( INITIAL_SIZE ), |
209 | 0 | _size( 0 ) |
210 | 0 | { |
211 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::XMLNode*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<char const*, 10>::DynArray() Unexecuted instantiation: tinyxml2::DynArray<char, 20>::DynArray() |
212 | | |
213 | 0 | ~DynArray() { |
214 | 0 | if ( _mem != _pool ) { |
215 | 0 | delete [] _mem; |
216 | 0 | } |
217 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<char const*, 10>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<char, 20>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::XMLNode*, 10>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::~DynArray() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::~DynArray() |
218 | | |
219 | 0 | void Clear() { |
220 | 0 | _size = 0; |
221 | 0 | } |
222 | | |
223 | 0 | void Push( T t ) { |
224 | 0 | TIXMLASSERT( _size < INT_MAX ); |
225 | 0 | EnsureCapacity( _size+1 ); |
226 | 0 | _mem[_size] = t; |
227 | 0 | ++_size; |
228 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<char, 20>::Push(char) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::XMLNode*, 10>::Push(tinyxml2::XMLNode*) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::Push(tinyxml2::MemPoolT<80>::Block*) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::Push(tinyxml2::MemPoolT<120>::Block*) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::Push(tinyxml2::MemPoolT<112>::Block*) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::Push(tinyxml2::MemPoolT<104>::Block*) Unexecuted instantiation: tinyxml2::DynArray<char const*, 10>::Push(char const*) |
229 | | |
230 | 0 | T* PushArr( int count ) { |
231 | 0 | TIXMLASSERT( count >= 0 ); |
232 | 0 | TIXMLASSERT( _size <= INT_MAX - count ); |
233 | 0 | EnsureCapacity( _size+count ); |
234 | 0 | T* ret = &_mem[_size]; |
235 | 0 | _size += count; |
236 | 0 | return ret; |
237 | 0 | } |
238 | | |
239 | 0 | T Pop() { |
240 | 0 | TIXMLASSERT( _size > 0 ); |
241 | 0 | --_size; |
242 | 0 | return _mem[_size]; |
243 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::Pop() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::Pop() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::Pop() Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::Pop() Unexecuted instantiation: tinyxml2::DynArray<char const*, 10>::Pop() |
244 | | |
245 | | void PopArr( int count ) { |
246 | | TIXMLASSERT( _size >= count ); |
247 | | _size -= count; |
248 | | } |
249 | | |
250 | 0 | bool Empty() const { |
251 | 0 | return _size == 0; |
252 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::Empty() const Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::Empty() const Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::Empty() const Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::Empty() const |
253 | | |
254 | 0 | T& operator[](int i) { |
255 | 0 | TIXMLASSERT( i>= 0 && i < _size ); |
256 | 0 | return _mem[i]; |
257 | 0 | } |
258 | | |
259 | | const T& operator[](int i) const { |
260 | | TIXMLASSERT( i>= 0 && i < _size ); |
261 | | return _mem[i]; |
262 | | } |
263 | | |
264 | | const T& PeekTop() const { |
265 | | TIXMLASSERT( _size > 0 ); |
266 | | return _mem[ _size - 1]; |
267 | | } |
268 | | |
269 | 0 | int Size() const { |
270 | 0 | TIXMLASSERT( _size >= 0 ); |
271 | 0 | return _size; |
272 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::XMLNode*, 10>::Size() const Unexecuted instantiation: tinyxml2::DynArray<char, 20>::Size() const |
273 | | |
274 | | int Capacity() const { |
275 | | TIXMLASSERT( _allocated >= INITIAL_SIZE ); |
276 | | return _allocated; |
277 | | } |
278 | | |
279 | 0 | void SwapRemove(int i) { |
280 | 0 | TIXMLASSERT(i >= 0 && i < _size); |
281 | 0 | TIXMLASSERT(_size > 0); |
282 | 0 | _mem[i] = _mem[_size - 1]; |
283 | 0 | --_size; |
284 | 0 | } |
285 | | |
286 | 0 | const T* Mem() const { |
287 | 0 | TIXMLASSERT( _mem ); |
288 | 0 | return _mem; |
289 | 0 | } |
290 | | |
291 | | T* Mem() { |
292 | | TIXMLASSERT( _mem ); |
293 | | return _mem; |
294 | | } |
295 | | |
296 | | private: |
297 | | DynArray( const DynArray& ); // not supported |
298 | | void operator=( const DynArray& ); // not supported |
299 | | |
300 | 0 | void EnsureCapacity( int cap ) { |
301 | 0 | TIXMLASSERT( cap > 0 ); |
302 | 0 | if ( cap > _allocated ) { |
303 | 0 | TIXMLASSERT( cap <= INT_MAX / 2 ); |
304 | 0 | const int newAllocated = cap * 2; |
305 | 0 | T* newMem = new T[static_cast<unsigned int>(newAllocated)]; |
306 | 0 | TIXMLASSERT( newAllocated >= _size ); |
307 | 0 | memcpy( newMem, _mem, sizeof(T)*static_cast<size_t>(_size) ); // warning: not using constructors, only works for PODs |
308 | 0 | if ( _mem != _pool ) { |
309 | 0 | delete [] _mem; |
310 | 0 | } |
311 | 0 | _mem = newMem; |
312 | 0 | _allocated = newAllocated; |
313 | 0 | } |
314 | 0 | } Unexecuted instantiation: tinyxml2::DynArray<char, 20>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::XMLNode*, 10>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<80>::Block*, 10>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<120>::Block*, 10>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<112>::Block*, 10>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<tinyxml2::MemPoolT<104>::Block*, 10>::EnsureCapacity(int) Unexecuted instantiation: tinyxml2::DynArray<char const*, 10>::EnsureCapacity(int) |
315 | | |
316 | | T* _mem; |
317 | | T _pool[static_cast<size_t>(INITIAL_SIZE)]; |
318 | | int _allocated; // objects allocated |
319 | | int _size; // number objects in use |
320 | | }; |
321 | | |
322 | | |
323 | | /* |
324 | | Parent virtual class of a pool for fast allocation |
325 | | and deallocation of objects. |
326 | | */ |
327 | | class MemPool |
328 | | { |
329 | | public: |
330 | 0 | MemPool() {} |
331 | 0 | virtual ~MemPool() {} |
332 | | |
333 | | virtual int ItemSize() const = 0; |
334 | | virtual void* Alloc() = 0; |
335 | | virtual void Free( void* ) = 0; |
336 | | virtual void SetTracked() = 0; |
337 | | }; |
338 | | |
339 | | |
340 | | /* |
341 | | Template child class to create pools of the correct type. |
342 | | */ |
343 | | template< int ITEM_SIZE > |
344 | | class MemPoolT : public MemPool |
345 | | { |
346 | | public: |
347 | 0 | MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} Unexecuted instantiation: tinyxml2::MemPoolT<120>::MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<80>::MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<112>::MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<104>::MemPoolT() |
348 | 0 | ~MemPoolT() { |
349 | 0 | MemPoolT< ITEM_SIZE >::Clear(); |
350 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<120>::~MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<80>::~MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<112>::~MemPoolT() Unexecuted instantiation: tinyxml2::MemPoolT<104>::~MemPoolT() |
351 | | |
352 | 0 | void Clear() { |
353 | | // Delete the blocks. |
354 | 0 | while( !_blockPtrs.Empty()) { |
355 | 0 | Block* lastBlock = _blockPtrs.Pop(); |
356 | 0 | delete lastBlock; |
357 | 0 | } |
358 | 0 | _root = 0; |
359 | 0 | _currentAllocs = 0; |
360 | 0 | _nAllocs = 0; |
361 | 0 | _maxAllocs = 0; |
362 | 0 | _nUntracked = 0; |
363 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<120>::Clear() Unexecuted instantiation: tinyxml2::MemPoolT<80>::Clear() Unexecuted instantiation: tinyxml2::MemPoolT<112>::Clear() Unexecuted instantiation: tinyxml2::MemPoolT<104>::Clear() |
364 | | |
365 | 0 | virtual int ItemSize() const override{ |
366 | 0 | return ITEM_SIZE; |
367 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<120>::ItemSize() const Unexecuted instantiation: tinyxml2::MemPoolT<80>::ItemSize() const Unexecuted instantiation: tinyxml2::MemPoolT<112>::ItemSize() const Unexecuted instantiation: tinyxml2::MemPoolT<104>::ItemSize() const |
368 | | int CurrentAllocs() const { |
369 | | return _currentAllocs; |
370 | | } |
371 | | |
372 | 0 | virtual void* Alloc() override{ |
373 | 0 | if ( !_root ) { |
374 | | // Need a new block. |
375 | 0 | Block* block = new Block; |
376 | 0 | _blockPtrs.Push( block ); |
377 | |
|
378 | 0 | Item* blockItems = block->items; |
379 | 0 | for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { |
380 | 0 | blockItems[i].next = &(blockItems[i + 1]); |
381 | 0 | } |
382 | 0 | blockItems[ITEMS_PER_BLOCK - 1].next = 0; |
383 | 0 | _root = blockItems; |
384 | 0 | } |
385 | 0 | Item* const result = _root; |
386 | 0 | TIXMLASSERT( result != 0 ); |
387 | 0 | _root = _root->next; |
388 | |
|
389 | 0 | ++_currentAllocs; |
390 | 0 | if ( _currentAllocs > _maxAllocs ) { |
391 | 0 | _maxAllocs = _currentAllocs; |
392 | 0 | } |
393 | 0 | ++_nAllocs; |
394 | 0 | ++_nUntracked; |
395 | 0 | return result; |
396 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<80>::Alloc() Unexecuted instantiation: tinyxml2::MemPoolT<120>::Alloc() Unexecuted instantiation: tinyxml2::MemPoolT<112>::Alloc() Unexecuted instantiation: tinyxml2::MemPoolT<104>::Alloc() |
397 | | |
398 | 0 | virtual void Free( void* mem ) override { |
399 | 0 | if ( !mem ) { |
400 | 0 | return; |
401 | 0 | } |
402 | 0 | --_currentAllocs; |
403 | 0 | Item* item = static_cast<Item*>( mem ); |
404 | | #ifdef TINYXML2_DEBUG |
405 | | memset( item, 0xfe, sizeof( *item ) ); |
406 | | #endif |
407 | 0 | item->next = _root; |
408 | 0 | _root = item; |
409 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<120>::Free(void*) Unexecuted instantiation: tinyxml2::MemPoolT<80>::Free(void*) Unexecuted instantiation: tinyxml2::MemPoolT<112>::Free(void*) Unexecuted instantiation: tinyxml2::MemPoolT<104>::Free(void*) |
410 | | void Trace( const char* name ) { |
411 | | printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", |
412 | | name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, |
413 | | ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); |
414 | | } |
415 | | |
416 | 0 | void SetTracked() override { |
417 | 0 | --_nUntracked; |
418 | 0 | } Unexecuted instantiation: tinyxml2::MemPoolT<120>::SetTracked() Unexecuted instantiation: tinyxml2::MemPoolT<80>::SetTracked() Unexecuted instantiation: tinyxml2::MemPoolT<112>::SetTracked() Unexecuted instantiation: tinyxml2::MemPoolT<104>::SetTracked() |
419 | | |
420 | | int Untracked() const { |
421 | | return _nUntracked; |
422 | | } |
423 | | |
424 | | // This number is perf sensitive. 4k seems like a good tradeoff on my machine. |
425 | | // The test file is large, 170k. |
426 | | // Release: VS2010 gcc(no opt) |
427 | | // 1k: 4000 |
428 | | // 2k: 4000 |
429 | | // 4k: 3900 21000 |
430 | | // 16k: 5200 |
431 | | // 32k: 4300 |
432 | | // 64k: 4000 21000 |
433 | | // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK |
434 | | // in private part if ITEMS_PER_BLOCK is private |
435 | | enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; |
436 | | |
437 | | private: |
438 | | MemPoolT( const MemPoolT& ); // not supported |
439 | | void operator=( const MemPoolT& ); // not supported |
440 | | |
441 | | union Item { |
442 | | Item* next; |
443 | | char itemData[static_cast<size_t>(ITEM_SIZE)]; |
444 | | }; |
445 | | struct Block { |
446 | | Item items[ITEMS_PER_BLOCK]; |
447 | | }; |
448 | | DynArray< Block*, 10 > _blockPtrs; |
449 | | Item* _root; |
450 | | |
451 | | int _currentAllocs; |
452 | | int _nAllocs; |
453 | | int _maxAllocs; |
454 | | int _nUntracked; |
455 | | }; |
456 | | |
457 | | |
458 | | |
459 | | /** |
460 | | Implements the interface to the "Visitor pattern" (see the Accept() method.) |
461 | | If you call the Accept() method, it requires being passed a XMLVisitor |
462 | | class to handle callbacks. For nodes that contain other nodes (Document, Element) |
463 | | you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs |
464 | | are simply called with Visit(). |
465 | | |
466 | | If you return 'true' from a Visit method, recursive parsing will continue. If you return |
467 | | false, <b>no children of this node or its siblings</b> will be visited. |
468 | | |
469 | | All flavors of Visit methods have a default implementation that returns 'true' (continue |
470 | | visiting). You need to only override methods that are interesting to you. |
471 | | |
472 | | Generally Accept() is called on the XMLDocument, although all nodes support visiting. |
473 | | |
474 | | You should never change the document from a callback. |
475 | | |
476 | | @sa XMLNode::Accept() |
477 | | */ |
478 | | class TINYXML2_LIB XMLVisitor |
479 | | { |
480 | | public: |
481 | 0 | virtual ~XMLVisitor() {} |
482 | | |
483 | | /// Visit a document. |
484 | 0 | virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { |
485 | 0 | return true; |
486 | 0 | } |
487 | | /// Visit a document. |
488 | 0 | virtual bool VisitExit( const XMLDocument& /*doc*/ ) { |
489 | 0 | return true; |
490 | 0 | } |
491 | | |
492 | | /// Visit an element. |
493 | 0 | virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { |
494 | 0 | return true; |
495 | 0 | } |
496 | | /// Visit an element. |
497 | 0 | virtual bool VisitExit( const XMLElement& /*element*/ ) { |
498 | 0 | return true; |
499 | 0 | } |
500 | | |
501 | | /// Visit a declaration. |
502 | 0 | virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { |
503 | 0 | return true; |
504 | 0 | } |
505 | | /// Visit a text node. |
506 | 0 | virtual bool Visit( const XMLText& /*text*/ ) { |
507 | 0 | return true; |
508 | 0 | } |
509 | | /// Visit a comment node. |
510 | 0 | virtual bool Visit( const XMLComment& /*comment*/ ) { |
511 | 0 | return true; |
512 | 0 | } |
513 | | /// Visit an unknown node. |
514 | 0 | virtual bool Visit( const XMLUnknown& /*unknown*/ ) { |
515 | 0 | return true; |
516 | 0 | } |
517 | | }; |
518 | | |
519 | | // WARNING: must match XMLDocument::_errorNames[] |
520 | | enum XMLError { |
521 | | XML_SUCCESS = 0, |
522 | | XML_NO_ATTRIBUTE, |
523 | | XML_WRONG_ATTRIBUTE_TYPE, |
524 | | XML_ERROR_FILE_NOT_FOUND, |
525 | | XML_ERROR_FILE_COULD_NOT_BE_OPENED, |
526 | | XML_ERROR_FILE_READ_ERROR, |
527 | | XML_ERROR_PARSING_ELEMENT, |
528 | | XML_ERROR_PARSING_ATTRIBUTE, |
529 | | XML_ERROR_PARSING_TEXT, |
530 | | XML_ERROR_PARSING_CDATA, |
531 | | XML_ERROR_PARSING_COMMENT, |
532 | | XML_ERROR_PARSING_DECLARATION, |
533 | | XML_ERROR_PARSING_UNKNOWN, |
534 | | XML_ERROR_EMPTY_DOCUMENT, |
535 | | XML_ERROR_MISMATCHED_ELEMENT, |
536 | | XML_ERROR_PARSING, |
537 | | XML_CAN_NOT_CONVERT_TEXT, |
538 | | XML_NO_TEXT_NODE, |
539 | | XML_ELEMENT_DEPTH_EXCEEDED, |
540 | | |
541 | | XML_ERROR_COUNT |
542 | | }; |
543 | | |
544 | | |
545 | | /* |
546 | | Utility functionality. |
547 | | */ |
548 | | class TINYXML2_LIB XMLUtil |
549 | | { |
550 | | public: |
551 | 0 | static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { |
552 | 0 | TIXMLASSERT( p ); |
553 | |
|
554 | 0 | while( IsWhiteSpace(*p) ) { |
555 | 0 | if (curLineNumPtr && *p == '\n') { |
556 | 0 | ++(*curLineNumPtr); |
557 | 0 | } |
558 | 0 | ++p; |
559 | 0 | } |
560 | 0 | TIXMLASSERT( p ); |
561 | 0 | return p; |
562 | 0 | } |
563 | 0 | static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { |
564 | 0 | return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) ); |
565 | 0 | } |
566 | | |
567 | | // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't |
568 | | // correct, but simple, and usually works. |
569 | 0 | static bool IsWhiteSpace( char p ) { |
570 | 0 | return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); |
571 | 0 | } |
572 | | |
573 | 0 | inline static bool IsNameStartChar( unsigned char ch ) { |
574 | 0 | if ( ch >= 128 ) { |
575 | | // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() |
576 | 0 | return true; |
577 | 0 | } |
578 | 0 | if ( isalpha( ch ) ) { |
579 | 0 | return true; |
580 | 0 | } |
581 | 0 | return ch == ':' || ch == '_'; |
582 | 0 | } |
583 | | |
584 | 0 | inline static bool IsNameChar( unsigned char ch ) { |
585 | 0 | return IsNameStartChar( ch ) |
586 | 0 | || isdigit( ch ) |
587 | 0 | || ch == '.' |
588 | 0 | || ch == '-'; |
589 | 0 | } |
590 | | |
591 | 0 | inline static bool IsPrefixHex( const char* p) { |
592 | 0 | p = SkipWhiteSpace(p, 0); |
593 | 0 | return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); |
594 | 0 | } |
595 | | |
596 | 0 | inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { |
597 | 0 | if ( p == q ) { |
598 | 0 | return true; |
599 | 0 | } |
600 | 0 | TIXMLASSERT( p ); |
601 | 0 | TIXMLASSERT( q ); |
602 | 0 | TIXMLASSERT( nChar >= 0 ); |
603 | 0 | return strncmp( p, q, static_cast<size_t>(nChar) ) == 0; |
604 | 0 | } |
605 | | |
606 | 0 | inline static bool IsUTF8Continuation( const char p ) { |
607 | 0 | return ( p & 0x80 ) != 0; |
608 | 0 | } |
609 | | |
610 | | static const char* ReadBOM( const char* p, bool* hasBOM ); |
611 | | // p is the starting location, |
612 | | // the UTF-8 value of the entity will be placed in value, and length filled in. |
613 | | static const char* GetCharacterRef( const char* p, char* value, int* length ); |
614 | | static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); |
615 | | |
616 | | // converts primitive types to strings |
617 | | static void ToStr( int v, char* buffer, int bufferSize ); |
618 | | static void ToStr( unsigned v, char* buffer, int bufferSize ); |
619 | | static void ToStr( bool v, char* buffer, int bufferSize ); |
620 | | static void ToStr( float v, char* buffer, int bufferSize ); |
621 | | static void ToStr( double v, char* buffer, int bufferSize ); |
622 | | static void ToStr(int64_t v, char* buffer, int bufferSize); |
623 | | static void ToStr(uint64_t v, char* buffer, int bufferSize); |
624 | | |
625 | | // converts strings to primitive types |
626 | | static bool ToInt( const char* str, int* value ); |
627 | | static bool ToUnsigned( const char* str, unsigned* value ); |
628 | | static bool ToBool( const char* str, bool* value ); |
629 | | static bool ToFloat( const char* str, float* value ); |
630 | | static bool ToDouble( const char* str, double* value ); |
631 | | static bool ToInt64(const char* str, int64_t* value); |
632 | | static bool ToUnsigned64(const char* str, uint64_t* value); |
633 | | // Changes what is serialized for a boolean value. |
634 | | // Default to "true" and "false". Shouldn't be changed |
635 | | // unless you have a special testing or compatibility need. |
636 | | // Be careful: static, global, & not thread safe. |
637 | | // Be sure to set static const memory as parameters. |
638 | | static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); |
639 | | |
640 | | private: |
641 | | static const char* writeBoolTrue; |
642 | | static const char* writeBoolFalse; |
643 | | }; |
644 | | |
645 | | |
646 | | /** XMLNode is a base class for every object that is in the |
647 | | XML Document Object Model (DOM), except XMLAttributes. |
648 | | Nodes have siblings, a parent, and children which can |
649 | | be navigated. A node is always in a XMLDocument. |
650 | | The type of a XMLNode can be queried, and it can |
651 | | be cast to its more defined type. |
652 | | |
653 | | A XMLDocument allocates memory for all its Nodes. |
654 | | When the XMLDocument gets deleted, all its Nodes |
655 | | will also be deleted. |
656 | | |
657 | | @verbatim |
658 | | A Document can contain: Element (container or leaf) |
659 | | Comment (leaf) |
660 | | Unknown (leaf) |
661 | | Declaration( leaf ) |
662 | | |
663 | | An Element can contain: Element (container or leaf) |
664 | | Text (leaf) |
665 | | Attributes (not on tree) |
666 | | Comment (leaf) |
667 | | Unknown (leaf) |
668 | | |
669 | | @endverbatim |
670 | | */ |
671 | | class TINYXML2_LIB XMLNode |
672 | | { |
673 | | friend class XMLDocument; |
674 | | friend class XMLElement; |
675 | | public: |
676 | | |
677 | | /// Get the XMLDocument that owns this XMLNode. |
678 | 0 | const XMLDocument* GetDocument() const { |
679 | 0 | TIXMLASSERT( _document ); |
680 | 0 | return _document; |
681 | 0 | } |
682 | | /// Get the XMLDocument that owns this XMLNode. |
683 | 0 | XMLDocument* GetDocument() { |
684 | 0 | TIXMLASSERT( _document ); |
685 | 0 | return _document; |
686 | 0 | } |
687 | | |
688 | | /// Safely cast to an Element, or null. |
689 | 0 | virtual XMLElement* ToElement() { |
690 | 0 | return 0; |
691 | 0 | } |
692 | | /// Safely cast to Text, or null. |
693 | 0 | virtual XMLText* ToText() { |
694 | 0 | return 0; |
695 | 0 | } |
696 | | /// Safely cast to a Comment, or null. |
697 | 0 | virtual XMLComment* ToComment() { |
698 | 0 | return 0; |
699 | 0 | } |
700 | | /// Safely cast to a Document, or null. |
701 | 0 | virtual XMLDocument* ToDocument() { |
702 | 0 | return 0; |
703 | 0 | } |
704 | | /// Safely cast to a Declaration, or null. |
705 | 0 | virtual XMLDeclaration* ToDeclaration() { |
706 | 0 | return 0; |
707 | 0 | } |
708 | | /// Safely cast to an Unknown, or null. |
709 | 0 | virtual XMLUnknown* ToUnknown() { |
710 | 0 | return 0; |
711 | 0 | } |
712 | | |
713 | 0 | virtual const XMLElement* ToElement() const { |
714 | 0 | return 0; |
715 | 0 | } |
716 | 0 | virtual const XMLText* ToText() const { |
717 | 0 | return 0; |
718 | 0 | } |
719 | 0 | virtual const XMLComment* ToComment() const { |
720 | 0 | return 0; |
721 | 0 | } |
722 | 0 | virtual const XMLDocument* ToDocument() const { |
723 | 0 | return 0; |
724 | 0 | } |
725 | 0 | virtual const XMLDeclaration* ToDeclaration() const { |
726 | 0 | return 0; |
727 | 0 | } |
728 | 0 | virtual const XMLUnknown* ToUnknown() const { |
729 | 0 | return 0; |
730 | 0 | } |
731 | | |
732 | | // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. |
733 | | |
734 | | int ChildElementCount(const char *value) const; |
735 | | |
736 | | int ChildElementCount() const; |
737 | | |
738 | | /** The meaning of 'value' changes for the specific type. |
739 | | @verbatim |
740 | | Document: empty (NULL is returned, not an empty string) |
741 | | Element: name of the element |
742 | | Comment: the comment text |
743 | | Unknown: the tag contents |
744 | | Text: the text string |
745 | | @endverbatim |
746 | | */ |
747 | | const char* Value() const; |
748 | | |
749 | | /** Set the Value of an XML node. |
750 | | @sa Value() |
751 | | */ |
752 | | void SetValue( const char* val, bool staticMem=false ); |
753 | | |
754 | | /// Gets the line number the node is in, if the document was parsed from a file. |
755 | 0 | int GetLineNum() const { return _parseLineNum; } |
756 | | |
757 | | /// Get the parent of this node on the DOM. |
758 | 0 | const XMLNode* Parent() const { |
759 | 0 | return _parent; |
760 | 0 | } |
761 | | |
762 | 0 | XMLNode* Parent() { |
763 | 0 | return _parent; |
764 | 0 | } |
765 | | |
766 | | /// Returns true if this node has no children. |
767 | 0 | bool NoChildren() const { |
768 | 0 | return !_firstChild; |
769 | 0 | } |
770 | | |
771 | | /// Get the first child node, or null if none exists. |
772 | 0 | const XMLNode* FirstChild() const { |
773 | 0 | return _firstChild; |
774 | 0 | } |
775 | | |
776 | 0 | XMLNode* FirstChild() { |
777 | 0 | return _firstChild; |
778 | 0 | } |
779 | | |
780 | | /** Get the first child element, or optionally the first child |
781 | | element with the specified name. |
782 | | */ |
783 | | const XMLElement* FirstChildElement( const char* name = 0 ) const; |
784 | | |
785 | 0 | XMLElement* FirstChildElement( const char* name = 0 ) { |
786 | 0 | return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name )); |
787 | 0 | } |
788 | | |
789 | | /// Get the last child node, or null if none exists. |
790 | 0 | const XMLNode* LastChild() const { |
791 | 0 | return _lastChild; |
792 | 0 | } |
793 | | |
794 | 0 | XMLNode* LastChild() { |
795 | 0 | return _lastChild; |
796 | 0 | } |
797 | | |
798 | | /** Get the last child element or optionally the last child |
799 | | element with the specified name. |
800 | | */ |
801 | | const XMLElement* LastChildElement( const char* name = 0 ) const; |
802 | | |
803 | 0 | XMLElement* LastChildElement( const char* name = 0 ) { |
804 | 0 | return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) ); |
805 | 0 | } |
806 | | |
807 | | /// Get the previous (left) sibling node of this node. |
808 | 0 | const XMLNode* PreviousSibling() const { |
809 | 0 | return _prev; |
810 | 0 | } |
811 | | |
812 | 0 | XMLNode* PreviousSibling() { |
813 | 0 | return _prev; |
814 | 0 | } |
815 | | |
816 | | /// Get the previous (left) sibling element of this node, with an optionally supplied name. |
817 | | const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; |
818 | | |
819 | 0 | XMLElement* PreviousSiblingElement( const char* name = 0 ) { |
820 | 0 | return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) ); |
821 | 0 | } |
822 | | |
823 | | /// Get the next (right) sibling node of this node. |
824 | 0 | const XMLNode* NextSibling() const { |
825 | 0 | return _next; |
826 | 0 | } |
827 | | |
828 | 0 | XMLNode* NextSibling() { |
829 | 0 | return _next; |
830 | 0 | } |
831 | | |
832 | | /// Get the next (right) sibling element of this node, with an optionally supplied name. |
833 | | const XMLElement* NextSiblingElement( const char* name = 0 ) const; |
834 | | |
835 | 0 | XMLElement* NextSiblingElement( const char* name = 0 ) { |
836 | 0 | return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) ); |
837 | 0 | } |
838 | | |
839 | | /** |
840 | | Add a child node as the last (right) child. |
841 | | If the child node is already part of the document, |
842 | | it is moved from its old location to the new location. |
843 | | Returns the addThis argument or 0 if the node does not |
844 | | belong to the same document. |
845 | | */ |
846 | | XMLNode* InsertEndChild( XMLNode* addThis ); |
847 | | |
848 | 0 | XMLNode* LinkEndChild( XMLNode* addThis ) { |
849 | 0 | return InsertEndChild( addThis ); |
850 | 0 | } |
851 | | /** |
852 | | Add a child node as the first (left) child. |
853 | | If the child node is already part of the document, |
854 | | it is moved from its old location to the new location. |
855 | | Returns the addThis argument or 0 if the node does not |
856 | | belong to the same document. |
857 | | */ |
858 | | XMLNode* InsertFirstChild( XMLNode* addThis ); |
859 | | /** |
860 | | Add a node after the specified child node. |
861 | | If the child node is already part of the document, |
862 | | it is moved from its old location to the new location. |
863 | | Returns the addThis argument or 0 if the afterThis node |
864 | | is not a child of this node, or if the node does not |
865 | | belong to the same document. |
866 | | */ |
867 | | XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); |
868 | | |
869 | | /** |
870 | | Delete all the children of this node. |
871 | | */ |
872 | | void DeleteChildren(); |
873 | | |
874 | | /** |
875 | | Delete a child of this node. |
876 | | */ |
877 | | void DeleteChild( XMLNode* node ); |
878 | | |
879 | | /** |
880 | | Make a copy of this node, but not its children. |
881 | | You may pass in a Document pointer that will be |
882 | | the owner of the new Node. If the 'document' is |
883 | | null, then the node returned will be allocated |
884 | | from the current Document. (this->GetDocument()) |
885 | | |
886 | | Note: if called on a XMLDocument, this will return null. |
887 | | */ |
888 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; |
889 | | |
890 | | /** |
891 | | Make a copy of this node and all its children. |
892 | | |
893 | | If the 'target' is null, then the nodes will |
894 | | be allocated in the current document. If 'target' |
895 | | is specified, the memory will be allocated is the |
896 | | specified XMLDocument. |
897 | | |
898 | | NOTE: This is probably not the correct tool to |
899 | | copy a document, since XMLDocuments can have multiple |
900 | | top level XMLNodes. You probably want to use |
901 | | XMLDocument::DeepCopy() |
902 | | */ |
903 | | XMLNode* DeepClone( XMLDocument* target ) const; |
904 | | |
905 | | /** |
906 | | Test if 2 nodes are the same, but don't test children. |
907 | | The 2 nodes do not need to be in the same Document. |
908 | | |
909 | | Note: if called on a XMLDocument, this will return false. |
910 | | */ |
911 | | virtual bool ShallowEqual( const XMLNode* compare ) const = 0; |
912 | | |
913 | | /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the |
914 | | XML tree will be conditionally visited and the host will be called back |
915 | | via the XMLVisitor interface. |
916 | | |
917 | | This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse |
918 | | the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this |
919 | | interface versus any other.) |
920 | | |
921 | | The interface has been based on ideas from: |
922 | | |
923 | | - http://www.saxproject.org/ |
924 | | - http://c2.com/cgi/wiki?HierarchicalVisitorPattern |
925 | | |
926 | | Which are both good references for "visiting". |
927 | | |
928 | | An example of using Accept(): |
929 | | @verbatim |
930 | | XMLPrinter printer; |
931 | | tinyxmlDoc.Accept( &printer ); |
932 | | const char* xmlcstr = printer.CStr(); |
933 | | @endverbatim |
934 | | */ |
935 | | virtual bool Accept( XMLVisitor* visitor ) const = 0; |
936 | | |
937 | | /** |
938 | | Set user data into the XMLNode. TinyXML-2 in |
939 | | no way processes or interprets user data. |
940 | | It is initially 0. |
941 | | */ |
942 | 0 | void SetUserData(void* userData) { _userData = userData; } |
943 | | |
944 | | /** |
945 | | Get user data set into the XMLNode. TinyXML-2 in |
946 | | no way processes or interprets user data. |
947 | | It is initially 0. |
948 | | */ |
949 | 0 | void* GetUserData() const { return _userData; } |
950 | | |
951 | | protected: |
952 | | explicit XMLNode( XMLDocument* ); |
953 | | virtual ~XMLNode(); |
954 | | |
955 | | virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); |
956 | | |
957 | | XMLDocument* _document; |
958 | | XMLNode* _parent; |
959 | | mutable StrPair _value; |
960 | | int _parseLineNum; |
961 | | |
962 | | XMLNode* _firstChild; |
963 | | XMLNode* _lastChild; |
964 | | |
965 | | XMLNode* _prev; |
966 | | XMLNode* _next; |
967 | | |
968 | | void* _userData; |
969 | | |
970 | | private: |
971 | | MemPool* _memPool; |
972 | | void Unlink( XMLNode* child ); |
973 | | static void DeleteNode( XMLNode* node ); |
974 | | void InsertChildPreamble( XMLNode* insertThis ) const; |
975 | | const XMLElement* ToElementWithName( const char* name ) const; |
976 | | |
977 | | XMLNode( const XMLNode& ); // not supported |
978 | | XMLNode& operator=( const XMLNode& ); // not supported |
979 | | }; |
980 | | |
981 | | |
982 | | /** XML text. |
983 | | |
984 | | Note that a text node can have child element nodes, for example: |
985 | | @verbatim |
986 | | <root>This is <b>bold</b></root> |
987 | | @endverbatim |
988 | | |
989 | | A text node can have 2 ways to output the next. "normal" output |
990 | | and CDATA. It will default to the mode it was parsed from the XML file and |
991 | | you generally want to leave it alone, but you can change the output mode with |
992 | | SetCData() and query it with CData(). |
993 | | */ |
994 | | class TINYXML2_LIB XMLText : public XMLNode |
995 | | { |
996 | | friend class XMLDocument; |
997 | | public: |
998 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
999 | | |
1000 | 0 | virtual XMLText* ToText() override { |
1001 | 0 | return this; |
1002 | 0 | } |
1003 | 0 | virtual const XMLText* ToText() const override { |
1004 | 0 | return this; |
1005 | 0 | } |
1006 | | |
1007 | | /// Declare whether this should be CDATA or standard text. |
1008 | 0 | void SetCData( bool isCData ) { |
1009 | 0 | _isCData = isCData; |
1010 | 0 | } |
1011 | | /// Returns true if this is a CDATA text element. |
1012 | 0 | bool CData() const { |
1013 | 0 | return _isCData; |
1014 | 0 | } |
1015 | | |
1016 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const override; |
1017 | | virtual bool ShallowEqual( const XMLNode* compare ) const override; |
1018 | | |
1019 | | protected: |
1020 | 0 | explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} |
1021 | 0 | virtual ~XMLText() {} |
1022 | | |
1023 | | char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; |
1024 | | |
1025 | | private: |
1026 | | bool _isCData; |
1027 | | |
1028 | | XMLText( const XMLText& ); // not supported |
1029 | | XMLText& operator=( const XMLText& ); // not supported |
1030 | | }; |
1031 | | |
1032 | | |
1033 | | /** An XML Comment. */ |
1034 | | class TINYXML2_LIB XMLComment : public XMLNode |
1035 | | { |
1036 | | friend class XMLDocument; |
1037 | | public: |
1038 | 0 | virtual XMLComment* ToComment() override { |
1039 | 0 | return this; |
1040 | 0 | } |
1041 | 0 | virtual const XMLComment* ToComment() const override { |
1042 | 0 | return this; |
1043 | 0 | } |
1044 | | |
1045 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
1046 | | |
1047 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const override; |
1048 | | virtual bool ShallowEqual( const XMLNode* compare ) const override; |
1049 | | |
1050 | | protected: |
1051 | | explicit XMLComment( XMLDocument* doc ); |
1052 | | virtual ~XMLComment(); |
1053 | | |
1054 | | char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override; |
1055 | | |
1056 | | private: |
1057 | | XMLComment( const XMLComment& ); // not supported |
1058 | | XMLComment& operator=( const XMLComment& ); // not supported |
1059 | | }; |
1060 | | |
1061 | | |
1062 | | /** In correct XML the declaration is the first entry in the file. |
1063 | | @verbatim |
1064 | | <?xml version="1.0" standalone="yes"?> |
1065 | | @endverbatim |
1066 | | |
1067 | | TinyXML-2 will happily read or write files without a declaration, |
1068 | | however. |
1069 | | |
1070 | | The text of the declaration isn't interpreted. It is parsed |
1071 | | and written as a string. |
1072 | | */ |
1073 | | class TINYXML2_LIB XMLDeclaration : public XMLNode |
1074 | | { |
1075 | | friend class XMLDocument; |
1076 | | public: |
1077 | 0 | virtual XMLDeclaration* ToDeclaration() override { |
1078 | 0 | return this; |
1079 | 0 | } |
1080 | 0 | virtual const XMLDeclaration* ToDeclaration() const override { |
1081 | 0 | return this; |
1082 | 0 | } |
1083 | | |
1084 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
1085 | | |
1086 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const override; |
1087 | | virtual bool ShallowEqual( const XMLNode* compare ) const override; |
1088 | | |
1089 | | protected: |
1090 | | explicit XMLDeclaration( XMLDocument* doc ); |
1091 | | virtual ~XMLDeclaration(); |
1092 | | |
1093 | | char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; |
1094 | | |
1095 | | private: |
1096 | | XMLDeclaration( const XMLDeclaration& ); // not supported |
1097 | | XMLDeclaration& operator=( const XMLDeclaration& ); // not supported |
1098 | | }; |
1099 | | |
1100 | | |
1101 | | /** Any tag that TinyXML-2 doesn't recognize is saved as an |
1102 | | unknown. It is a tag of text, but should not be modified. |
1103 | | It will be written back to the XML, unchanged, when the file |
1104 | | is saved. |
1105 | | |
1106 | | DTD tags get thrown into XMLUnknowns. |
1107 | | */ |
1108 | | class TINYXML2_LIB XMLUnknown : public XMLNode |
1109 | | { |
1110 | | friend class XMLDocument; |
1111 | | public: |
1112 | 0 | virtual XMLUnknown* ToUnknown() override { |
1113 | 0 | return this; |
1114 | 0 | } |
1115 | 0 | virtual const XMLUnknown* ToUnknown() const override { |
1116 | 0 | return this; |
1117 | 0 | } |
1118 | | |
1119 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
1120 | | |
1121 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const override; |
1122 | | virtual bool ShallowEqual( const XMLNode* compare ) const override; |
1123 | | |
1124 | | protected: |
1125 | | explicit XMLUnknown( XMLDocument* doc ); |
1126 | | virtual ~XMLUnknown(); |
1127 | | |
1128 | | char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; |
1129 | | |
1130 | | private: |
1131 | | XMLUnknown( const XMLUnknown& ); // not supported |
1132 | | XMLUnknown& operator=( const XMLUnknown& ); // not supported |
1133 | | }; |
1134 | | |
1135 | | |
1136 | | |
1137 | | /** An attribute is a name-value pair. Elements have an arbitrary |
1138 | | number of attributes, each with a unique name. |
1139 | | |
1140 | | @note The attributes are not XMLNodes. You may only query the |
1141 | | Next() attribute in a list. |
1142 | | */ |
1143 | | class TINYXML2_LIB XMLAttribute |
1144 | | { |
1145 | | friend class XMLElement; |
1146 | | public: |
1147 | | /// The name of the attribute. |
1148 | | const char* Name() const; |
1149 | | |
1150 | | /// The value of the attribute. |
1151 | | const char* Value() const; |
1152 | | |
1153 | | /// Gets the line number the attribute is in, if the document was parsed from a file. |
1154 | 0 | int GetLineNum() const { return _parseLineNum; } |
1155 | | |
1156 | | /// The next attribute in the list. |
1157 | 0 | const XMLAttribute* Next() const { |
1158 | 0 | return _next; |
1159 | 0 | } |
1160 | | |
1161 | | /** IntValue interprets the attribute as an integer, and returns the value. |
1162 | | If the value isn't an integer, 0 will be returned. There is no error checking; |
1163 | | use QueryIntValue() if you need error checking. |
1164 | | */ |
1165 | 0 | int IntValue() const { |
1166 | 0 | int i = 0; |
1167 | 0 | QueryIntValue(&i); |
1168 | 0 | return i; |
1169 | 0 | } |
1170 | | |
1171 | 0 | int64_t Int64Value() const { |
1172 | 0 | int64_t i = 0; |
1173 | 0 | QueryInt64Value(&i); |
1174 | 0 | return i; |
1175 | 0 | } |
1176 | | |
1177 | 0 | uint64_t Unsigned64Value() const { |
1178 | 0 | uint64_t i = 0; |
1179 | 0 | QueryUnsigned64Value(&i); |
1180 | 0 | return i; |
1181 | 0 | } |
1182 | | |
1183 | | /// Query as an unsigned integer. See IntValue() |
1184 | 0 | unsigned UnsignedValue() const { |
1185 | 0 | unsigned i=0; |
1186 | 0 | QueryUnsignedValue( &i ); |
1187 | 0 | return i; |
1188 | 0 | } |
1189 | | /// Query as a boolean. See IntValue() |
1190 | 0 | bool BoolValue() const { |
1191 | 0 | bool b=false; |
1192 | 0 | QueryBoolValue( &b ); |
1193 | 0 | return b; |
1194 | 0 | } |
1195 | | /// Query as a double. See IntValue() |
1196 | 0 | double DoubleValue() const { |
1197 | 0 | double d=0; |
1198 | 0 | QueryDoubleValue( &d ); |
1199 | 0 | return d; |
1200 | 0 | } |
1201 | | /// Query as a float. See IntValue() |
1202 | 0 | float FloatValue() const { |
1203 | 0 | float f=0; |
1204 | 0 | QueryFloatValue( &f ); |
1205 | 0 | return f; |
1206 | 0 | } |
1207 | | |
1208 | | /** QueryIntValue interprets the attribute as an integer, and returns the value |
1209 | | in the provided parameter. The function will return XML_SUCCESS on success, |
1210 | | and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. |
1211 | | */ |
1212 | | XMLError QueryIntValue( int* value ) const; |
1213 | | /// See QueryIntValue |
1214 | | XMLError QueryUnsignedValue( unsigned int* value ) const; |
1215 | | /// See QueryIntValue |
1216 | | XMLError QueryInt64Value(int64_t* value) const; |
1217 | | /// See QueryIntValue |
1218 | | XMLError QueryUnsigned64Value(uint64_t* value) const; |
1219 | | /// See QueryIntValue |
1220 | | XMLError QueryBoolValue( bool* value ) const; |
1221 | | /// See QueryIntValue |
1222 | | XMLError QueryDoubleValue( double* value ) const; |
1223 | | /// See QueryIntValue |
1224 | | XMLError QueryFloatValue( float* value ) const; |
1225 | | |
1226 | | /// Set the attribute to a string value. |
1227 | | void SetAttribute( const char* value ); |
1228 | | /// Set the attribute to value. |
1229 | | void SetAttribute( int value ); |
1230 | | /// Set the attribute to value. |
1231 | | void SetAttribute( unsigned value ); |
1232 | | /// Set the attribute to value. |
1233 | | void SetAttribute(int64_t value); |
1234 | | /// Set the attribute to value. |
1235 | | void SetAttribute(uint64_t value); |
1236 | | /// Set the attribute to value. |
1237 | | void SetAttribute( bool value ); |
1238 | | /// Set the attribute to value. |
1239 | | void SetAttribute( double value ); |
1240 | | /// Set the attribute to value. |
1241 | | void SetAttribute( float value ); |
1242 | | |
1243 | | private: |
1244 | | enum { BUF_SIZE = 200 }; |
1245 | | |
1246 | 0 | XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} |
1247 | 0 | virtual ~XMLAttribute() {} |
1248 | | |
1249 | | XMLAttribute( const XMLAttribute& ); // not supported |
1250 | | void operator=( const XMLAttribute& ); // not supported |
1251 | | void SetName( const char* name ); |
1252 | | |
1253 | | char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); |
1254 | | |
1255 | | mutable StrPair _name; |
1256 | | mutable StrPair _value; |
1257 | | int _parseLineNum; |
1258 | | XMLAttribute* _next; |
1259 | | MemPool* _memPool; |
1260 | | }; |
1261 | | |
1262 | | |
1263 | | /** The element is a container class. It has a value, the element name, |
1264 | | and can contain other elements, text, comments, and unknowns. |
1265 | | Elements also contain an arbitrary number of attributes. |
1266 | | */ |
1267 | | class TINYXML2_LIB XMLElement : public XMLNode |
1268 | | { |
1269 | | friend class XMLDocument; |
1270 | | public: |
1271 | | /// Get the name of an element (which is the Value() of the node.) |
1272 | 0 | const char* Name() const { |
1273 | 0 | return Value(); |
1274 | 0 | } |
1275 | | /// Set the name of the element. |
1276 | 0 | void SetName( const char* str, bool staticMem=false ) { |
1277 | 0 | SetValue( str, staticMem ); |
1278 | 0 | } |
1279 | | |
1280 | 0 | virtual XMLElement* ToElement() override { |
1281 | 0 | return this; |
1282 | 0 | } |
1283 | 0 | virtual const XMLElement* ToElement() const override { |
1284 | 0 | return this; |
1285 | 0 | } |
1286 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
1287 | | |
1288 | | /** Given an attribute name, Attribute() returns the value |
1289 | | for the attribute of that name, or null if none |
1290 | | exists. For example: |
1291 | | |
1292 | | @verbatim |
1293 | | const char* value = ele->Attribute( "foo" ); |
1294 | | @endverbatim |
1295 | | |
1296 | | The 'value' parameter is normally null. However, if specified, |
1297 | | the attribute will only be returned if the 'name' and 'value' |
1298 | | match. This allow you to write code: |
1299 | | |
1300 | | @verbatim |
1301 | | if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); |
1302 | | @endverbatim |
1303 | | |
1304 | | rather than: |
1305 | | @verbatim |
1306 | | if ( ele->Attribute( "foo" ) ) { |
1307 | | if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); |
1308 | | } |
1309 | | @endverbatim |
1310 | | */ |
1311 | | const char* Attribute( const char* name, const char* value=0 ) const; |
1312 | | |
1313 | | /** Given an attribute name, IntAttribute() returns the value |
1314 | | of the attribute interpreted as an integer. The default |
1315 | | value will be returned if the attribute isn't present, |
1316 | | or if there is an error. (For a method with error |
1317 | | checking, see QueryIntAttribute()). |
1318 | | */ |
1319 | | int IntAttribute(const char* name, int defaultValue = 0) const; |
1320 | | /// See IntAttribute() |
1321 | | unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; |
1322 | | /// See IntAttribute() |
1323 | | int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; |
1324 | | /// See IntAttribute() |
1325 | | uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; |
1326 | | /// See IntAttribute() |
1327 | | bool BoolAttribute(const char* name, bool defaultValue = false) const; |
1328 | | /// See IntAttribute() |
1329 | | double DoubleAttribute(const char* name, double defaultValue = 0) const; |
1330 | | /// See IntAttribute() |
1331 | | float FloatAttribute(const char* name, float defaultValue = 0) const; |
1332 | | |
1333 | | /** Given an attribute name, QueryIntAttribute() returns |
1334 | | XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion |
1335 | | can't be performed, or XML_NO_ATTRIBUTE if the attribute |
1336 | | doesn't exist. If successful, the result of the conversion |
1337 | | will be written to 'value'. If not successful, nothing will |
1338 | | be written to 'value'. This allows you to provide default |
1339 | | value: |
1340 | | |
1341 | | @verbatim |
1342 | | int value = 10; |
1343 | | QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 |
1344 | | @endverbatim |
1345 | | */ |
1346 | 0 | XMLError QueryIntAttribute( const char* name, int* value ) const { |
1347 | 0 | const XMLAttribute* a = FindAttribute( name ); |
1348 | 0 | if ( !a ) { |
1349 | 0 | return XML_NO_ATTRIBUTE; |
1350 | 0 | } |
1351 | 0 | return a->QueryIntValue( value ); |
1352 | 0 | } |
1353 | | |
1354 | | /// See QueryIntAttribute() |
1355 | 0 | XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { |
1356 | 0 | const XMLAttribute* a = FindAttribute( name ); |
1357 | 0 | if ( !a ) { |
1358 | 0 | return XML_NO_ATTRIBUTE; |
1359 | 0 | } |
1360 | 0 | return a->QueryUnsignedValue( value ); |
1361 | 0 | } |
1362 | | |
1363 | | /// See QueryIntAttribute() |
1364 | 0 | XMLError QueryInt64Attribute(const char* name, int64_t* value) const { |
1365 | 0 | const XMLAttribute* a = FindAttribute(name); |
1366 | 0 | if (!a) { |
1367 | 0 | return XML_NO_ATTRIBUTE; |
1368 | 0 | } |
1369 | 0 | return a->QueryInt64Value(value); |
1370 | 0 | } |
1371 | | |
1372 | | /// See QueryIntAttribute() |
1373 | 0 | XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { |
1374 | 0 | const XMLAttribute* a = FindAttribute(name); |
1375 | 0 | if(!a) { |
1376 | 0 | return XML_NO_ATTRIBUTE; |
1377 | 0 | } |
1378 | 0 | return a->QueryUnsigned64Value(value); |
1379 | 0 | } |
1380 | | |
1381 | | /// See QueryIntAttribute() |
1382 | 0 | XMLError QueryBoolAttribute( const char* name, bool* value ) const { |
1383 | 0 | const XMLAttribute* a = FindAttribute( name ); |
1384 | 0 | if ( !a ) { |
1385 | 0 | return XML_NO_ATTRIBUTE; |
1386 | 0 | } |
1387 | 0 | return a->QueryBoolValue( value ); |
1388 | 0 | } |
1389 | | /// See QueryIntAttribute() |
1390 | 0 | XMLError QueryDoubleAttribute( const char* name, double* value ) const { |
1391 | 0 | const XMLAttribute* a = FindAttribute( name ); |
1392 | 0 | if ( !a ) { |
1393 | 0 | return XML_NO_ATTRIBUTE; |
1394 | 0 | } |
1395 | 0 | return a->QueryDoubleValue( value ); |
1396 | 0 | } |
1397 | | /// See QueryIntAttribute() |
1398 | 0 | XMLError QueryFloatAttribute( const char* name, float* value ) const { |
1399 | 0 | const XMLAttribute* a = FindAttribute( name ); |
1400 | 0 | if ( !a ) { |
1401 | 0 | return XML_NO_ATTRIBUTE; |
1402 | 0 | } |
1403 | 0 | return a->QueryFloatValue( value ); |
1404 | 0 | } |
1405 | | |
1406 | | /// See QueryIntAttribute() |
1407 | 0 | XMLError QueryStringAttribute(const char* name, const char** value) const { |
1408 | 0 | const XMLAttribute* a = FindAttribute(name); |
1409 | 0 | if (!a) { |
1410 | 0 | return XML_NO_ATTRIBUTE; |
1411 | 0 | } |
1412 | 0 | *value = a->Value(); |
1413 | 0 | return XML_SUCCESS; |
1414 | 0 | } |
1415 | | |
1416 | | |
1417 | | |
1418 | | /** Given an attribute name, QueryAttribute() returns |
1419 | | XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion |
1420 | | can't be performed, or XML_NO_ATTRIBUTE if the attribute |
1421 | | doesn't exist. It is overloaded for the primitive types, |
1422 | | and is a generally more convenient replacement of |
1423 | | QueryIntAttribute() and related functions. |
1424 | | |
1425 | | If successful, the result of the conversion |
1426 | | will be written to 'value'. If not successful, nothing will |
1427 | | be written to 'value'. This allows you to provide default |
1428 | | value: |
1429 | | |
1430 | | @verbatim |
1431 | | int value = 10; |
1432 | | QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 |
1433 | | @endverbatim |
1434 | | */ |
1435 | 0 | XMLError QueryAttribute( const char* name, int* value ) const { |
1436 | 0 | return QueryIntAttribute( name, value ); |
1437 | 0 | } |
1438 | | |
1439 | 0 | XMLError QueryAttribute( const char* name, unsigned int* value ) const { |
1440 | 0 | return QueryUnsignedAttribute( name, value ); |
1441 | 0 | } |
1442 | | |
1443 | 0 | XMLError QueryAttribute(const char* name, int64_t* value) const { |
1444 | 0 | return QueryInt64Attribute(name, value); |
1445 | 0 | } |
1446 | | |
1447 | 0 | XMLError QueryAttribute(const char* name, uint64_t* value) const { |
1448 | 0 | return QueryUnsigned64Attribute(name, value); |
1449 | 0 | } |
1450 | | |
1451 | 0 | XMLError QueryAttribute( const char* name, bool* value ) const { |
1452 | 0 | return QueryBoolAttribute( name, value ); |
1453 | 0 | } |
1454 | | |
1455 | 0 | XMLError QueryAttribute( const char* name, double* value ) const { |
1456 | 0 | return QueryDoubleAttribute( name, value ); |
1457 | 0 | } |
1458 | | |
1459 | 0 | XMLError QueryAttribute( const char* name, float* value ) const { |
1460 | 0 | return QueryFloatAttribute( name, value ); |
1461 | 0 | } |
1462 | | |
1463 | 0 | XMLError QueryAttribute(const char* name, const char** value) const { |
1464 | 0 | return QueryStringAttribute(name, value); |
1465 | 0 | } |
1466 | | |
1467 | | /// Sets the named attribute to value. |
1468 | 0 | void SetAttribute( const char* name, const char* value ) { |
1469 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1470 | 0 | a->SetAttribute( value ); |
1471 | 0 | } |
1472 | | /// Sets the named attribute to value. |
1473 | 0 | void SetAttribute( const char* name, int value ) { |
1474 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1475 | 0 | a->SetAttribute( value ); |
1476 | 0 | } |
1477 | | /// Sets the named attribute to value. |
1478 | 0 | void SetAttribute( const char* name, unsigned value ) { |
1479 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1480 | 0 | a->SetAttribute( value ); |
1481 | 0 | } |
1482 | | |
1483 | | /// Sets the named attribute to value. |
1484 | 0 | void SetAttribute(const char* name, int64_t value) { |
1485 | 0 | XMLAttribute* a = FindOrCreateAttribute(name); |
1486 | 0 | a->SetAttribute(value); |
1487 | 0 | } |
1488 | | |
1489 | | /// Sets the named attribute to value. |
1490 | 0 | void SetAttribute(const char* name, uint64_t value) { |
1491 | 0 | XMLAttribute* a = FindOrCreateAttribute(name); |
1492 | 0 | a->SetAttribute(value); |
1493 | 0 | } |
1494 | | |
1495 | | /// Sets the named attribute to value. |
1496 | 0 | void SetAttribute( const char* name, bool value ) { |
1497 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1498 | 0 | a->SetAttribute( value ); |
1499 | 0 | } |
1500 | | /// Sets the named attribute to value. |
1501 | 0 | void SetAttribute( const char* name, double value ) { |
1502 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1503 | 0 | a->SetAttribute( value ); |
1504 | 0 | } |
1505 | | /// Sets the named attribute to value. |
1506 | 0 | void SetAttribute( const char* name, float value ) { |
1507 | 0 | XMLAttribute* a = FindOrCreateAttribute( name ); |
1508 | 0 | a->SetAttribute( value ); |
1509 | 0 | } |
1510 | | |
1511 | | /** |
1512 | | Delete an attribute. |
1513 | | */ |
1514 | | void DeleteAttribute( const char* name ); |
1515 | | |
1516 | | /// Return the first attribute in the list. |
1517 | 0 | const XMLAttribute* FirstAttribute() const { |
1518 | 0 | return _rootAttribute; |
1519 | 0 | } |
1520 | | /// Query a specific attribute in the list. |
1521 | | const XMLAttribute* FindAttribute( const char* name ) const; |
1522 | | |
1523 | | /** Convenience function for easy access to the text inside an element. Although easy |
1524 | | and concise, GetText() is limited compared to getting the XMLText child |
1525 | | and accessing it directly. |
1526 | | |
1527 | | If the first child of 'this' is a XMLText, the GetText() |
1528 | | returns the character string of the Text node, else null is returned. |
1529 | | |
1530 | | This is a convenient method for getting the text of simple contained text: |
1531 | | @verbatim |
1532 | | <foo>This is text</foo> |
1533 | | const char* str = fooElement->GetText(); |
1534 | | @endverbatim |
1535 | | |
1536 | | 'str' will be a pointer to "This is text". |
1537 | | |
1538 | | Note that this function can be misleading. If the element foo was created from |
1539 | | this XML: |
1540 | | @verbatim |
1541 | | <foo><b>This is text</b></foo> |
1542 | | @endverbatim |
1543 | | |
1544 | | then the value of str would be null. The first child node isn't a text node, it is |
1545 | | another element. From this XML: |
1546 | | @verbatim |
1547 | | <foo>This is <b>text</b></foo> |
1548 | | @endverbatim |
1549 | | GetText() will return "This is ". |
1550 | | */ |
1551 | | const char* GetText() const; |
1552 | | |
1553 | | /** Convenience function for easy access to the text inside an element. Although easy |
1554 | | and concise, SetText() is limited compared to creating an XMLText child |
1555 | | and mutating it directly. |
1556 | | |
1557 | | If the first child of 'this' is a XMLText, SetText() sets its value to |
1558 | | the given string, otherwise it will create a first child that is an XMLText. |
1559 | | |
1560 | | This is a convenient method for setting the text of simple contained text: |
1561 | | @verbatim |
1562 | | <foo>This is text</foo> |
1563 | | fooElement->SetText( "Hullaballoo!" ); |
1564 | | <foo>Hullaballoo!</foo> |
1565 | | @endverbatim |
1566 | | |
1567 | | Note that this function can be misleading. If the element foo was created from |
1568 | | this XML: |
1569 | | @verbatim |
1570 | | <foo><b>This is text</b></foo> |
1571 | | @endverbatim |
1572 | | |
1573 | | then it will not change "This is text", but rather prefix it with a text element: |
1574 | | @verbatim |
1575 | | <foo>Hullaballoo!<b>This is text</b></foo> |
1576 | | @endverbatim |
1577 | | |
1578 | | For this XML: |
1579 | | @verbatim |
1580 | | <foo /> |
1581 | | @endverbatim |
1582 | | SetText() will generate |
1583 | | @verbatim |
1584 | | <foo>Hullaballoo!</foo> |
1585 | | @endverbatim |
1586 | | */ |
1587 | | void SetText( const char* inText ); |
1588 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1589 | | void SetText( int value ); |
1590 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1591 | | void SetText( unsigned value ); |
1592 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1593 | | void SetText(int64_t value); |
1594 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1595 | | void SetText(uint64_t value); |
1596 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1597 | | void SetText( bool value ); |
1598 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1599 | | void SetText( double value ); |
1600 | | /// Convenience method for setting text inside an element. See SetText() for important limitations. |
1601 | | void SetText( float value ); |
1602 | | |
1603 | | /** |
1604 | | Convenience method to query the value of a child text node. This is probably best |
1605 | | shown by example. Given you have a document is this form: |
1606 | | @verbatim |
1607 | | <point> |
1608 | | <x>1</x> |
1609 | | <y>1.4</y> |
1610 | | </point> |
1611 | | @endverbatim |
1612 | | |
1613 | | The QueryIntText() and similar functions provide a safe and easier way to get to the |
1614 | | "value" of x and y. |
1615 | | |
1616 | | @verbatim |
1617 | | int x = 0; |
1618 | | float y = 0; // types of x and y are contrived for example |
1619 | | const XMLElement* xElement = pointElement->FirstChildElement( "x" ); |
1620 | | const XMLElement* yElement = pointElement->FirstChildElement( "y" ); |
1621 | | xElement->QueryIntText( &x ); |
1622 | | yElement->QueryFloatText( &y ); |
1623 | | @endverbatim |
1624 | | |
1625 | | @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted |
1626 | | to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. |
1627 | | |
1628 | | */ |
1629 | | XMLError QueryIntText( int* ival ) const; |
1630 | | /// See QueryIntText() |
1631 | | XMLError QueryUnsignedText( unsigned* uval ) const; |
1632 | | /// See QueryIntText() |
1633 | | XMLError QueryInt64Text(int64_t* uval) const; |
1634 | | /// See QueryIntText() |
1635 | | XMLError QueryUnsigned64Text(uint64_t* uval) const; |
1636 | | /// See QueryIntText() |
1637 | | XMLError QueryBoolText( bool* bval ) const; |
1638 | | /// See QueryIntText() |
1639 | | XMLError QueryDoubleText( double* dval ) const; |
1640 | | /// See QueryIntText() |
1641 | | XMLError QueryFloatText( float* fval ) const; |
1642 | | |
1643 | | int IntText(int defaultValue = 0) const; |
1644 | | |
1645 | | /// See QueryIntText() |
1646 | | unsigned UnsignedText(unsigned defaultValue = 0) const; |
1647 | | /// See QueryIntText() |
1648 | | int64_t Int64Text(int64_t defaultValue = 0) const; |
1649 | | /// See QueryIntText() |
1650 | | uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; |
1651 | | /// See QueryIntText() |
1652 | | bool BoolText(bool defaultValue = false) const; |
1653 | | /// See QueryIntText() |
1654 | | double DoubleText(double defaultValue = 0) const; |
1655 | | /// See QueryIntText() |
1656 | | float FloatText(float defaultValue = 0) const; |
1657 | | |
1658 | | /** |
1659 | | Convenience method to create a new XMLElement and add it as last (right) |
1660 | | child of this node. Returns the created and inserted element. |
1661 | | */ |
1662 | | XMLElement* InsertNewChildElement(const char* name); |
1663 | | /// See InsertNewChildElement() |
1664 | | XMLComment* InsertNewComment(const char* comment); |
1665 | | /// See InsertNewChildElement() |
1666 | | XMLText* InsertNewText(const char* text); |
1667 | | /// See InsertNewChildElement() |
1668 | | XMLDeclaration* InsertNewDeclaration(const char* text); |
1669 | | /// See InsertNewChildElement() |
1670 | | XMLUnknown* InsertNewUnknown(const char* text); |
1671 | | |
1672 | | |
1673 | | // internal: |
1674 | | enum ElementClosingType { |
1675 | | OPEN, // <foo> |
1676 | | CLOSED, // <foo/> |
1677 | | CLOSING // </foo> |
1678 | | }; |
1679 | 0 | ElementClosingType ClosingType() const { |
1680 | 0 | return _closingType; |
1681 | 0 | } |
1682 | | virtual XMLNode* ShallowClone( XMLDocument* document ) const override; |
1683 | | virtual bool ShallowEqual( const XMLNode* compare ) const override; |
1684 | | |
1685 | | protected: |
1686 | | char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; |
1687 | | |
1688 | | private: |
1689 | | XMLElement( XMLDocument* doc ); |
1690 | | virtual ~XMLElement(); |
1691 | | XMLElement( const XMLElement& ); // not supported |
1692 | | void operator=( const XMLElement& ); // not supported |
1693 | | |
1694 | | XMLAttribute* FindOrCreateAttribute( const char* name ); |
1695 | | char* ParseAttributes( char* p, int* curLineNumPtr ); |
1696 | | static void DeleteAttribute( XMLAttribute* attribute ); |
1697 | | XMLAttribute* CreateAttribute(); |
1698 | | |
1699 | | enum { BUF_SIZE = 200 }; |
1700 | | ElementClosingType _closingType; |
1701 | | // The attribute list is ordered; there is no 'lastAttribute' |
1702 | | // because the list needs to be scanned for dupes before adding |
1703 | | // a new attribute. |
1704 | | XMLAttribute* _rootAttribute; |
1705 | | }; |
1706 | | |
1707 | | |
1708 | | enum Whitespace { |
1709 | | PRESERVE_WHITESPACE, |
1710 | | COLLAPSE_WHITESPACE, |
1711 | | PEDANTIC_WHITESPACE |
1712 | | }; |
1713 | | |
1714 | | |
1715 | | /** A Document binds together all the functionality. |
1716 | | It can be saved, loaded, and printed to the screen. |
1717 | | All Nodes are connected and allocated to a Document. |
1718 | | If the Document is deleted, all its Nodes are also deleted. |
1719 | | */ |
1720 | | class TINYXML2_LIB XMLDocument : public XMLNode |
1721 | | { |
1722 | | friend class XMLElement; |
1723 | | // Gives access to SetError and Push/PopDepth, but over-access for everything else. |
1724 | | // Wishing C++ had "internal" scope. |
1725 | | friend class XMLNode; |
1726 | | friend class XMLText; |
1727 | | friend class XMLComment; |
1728 | | friend class XMLDeclaration; |
1729 | | friend class XMLUnknown; |
1730 | | public: |
1731 | | /// constructor |
1732 | | XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); |
1733 | | ~XMLDocument(); |
1734 | | |
1735 | 0 | virtual XMLDocument* ToDocument() override { |
1736 | 0 | TIXMLASSERT( this == _document ); |
1737 | 0 | return this; |
1738 | 0 | } |
1739 | 0 | virtual const XMLDocument* ToDocument() const override { |
1740 | 0 | TIXMLASSERT( this == _document ); |
1741 | 0 | return this; |
1742 | 0 | } |
1743 | | |
1744 | | /** |
1745 | | Parse an XML file from a character string. |
1746 | | Returns XML_SUCCESS (0) on success, or |
1747 | | an errorID. |
1748 | | |
1749 | | You may optionally pass in the 'nBytes', which is |
1750 | | the number of bytes which will be parsed. If not |
1751 | | specified, TinyXML-2 will assume 'xml' points to a |
1752 | | null terminated string. |
1753 | | */ |
1754 | | XMLError Parse( const char* xml, size_t nBytes=static_cast<size_t>(-1) ); |
1755 | | |
1756 | | /** |
1757 | | Load an XML file from disk. |
1758 | | Returns XML_SUCCESS (0) on success, or |
1759 | | an errorID. |
1760 | | */ |
1761 | | XMLError LoadFile( const char* filename ); |
1762 | | |
1763 | | /** |
1764 | | Load an XML file from disk. You are responsible |
1765 | | for providing and closing the FILE*. |
1766 | | |
1767 | | NOTE: The file should be opened as binary ("rb") |
1768 | | not text in order for TinyXML-2 to correctly |
1769 | | do newline normalization. |
1770 | | |
1771 | | Returns XML_SUCCESS (0) on success, or |
1772 | | an errorID. |
1773 | | */ |
1774 | | XMLError LoadFile( FILE* ); |
1775 | | |
1776 | | /** |
1777 | | Save the XML file to disk. |
1778 | | Returns XML_SUCCESS (0) on success, or |
1779 | | an errorID. |
1780 | | */ |
1781 | | XMLError SaveFile( const char* filename, bool compact = false ); |
1782 | | |
1783 | | /** |
1784 | | Save the XML file to disk. You are responsible |
1785 | | for providing and closing the FILE*. |
1786 | | |
1787 | | Returns XML_SUCCESS (0) on success, or |
1788 | | an errorID. |
1789 | | */ |
1790 | | XMLError SaveFile( FILE* fp, bool compact = false ); |
1791 | | |
1792 | 0 | bool ProcessEntities() const { |
1793 | 0 | return _processEntities; |
1794 | 0 | } |
1795 | 0 | Whitespace WhitespaceMode() const { |
1796 | 0 | return _whitespaceMode; |
1797 | 0 | } |
1798 | | |
1799 | | /** |
1800 | | Returns true if this document has a leading Byte Order Mark of UTF8. |
1801 | | */ |
1802 | 0 | bool HasBOM() const { |
1803 | 0 | return _writeBOM; |
1804 | 0 | } |
1805 | | /** Sets whether to write the BOM when writing the file. |
1806 | | */ |
1807 | 0 | void SetBOM( bool useBOM ) { |
1808 | 0 | _writeBOM = useBOM; |
1809 | 0 | } |
1810 | | |
1811 | | /** Return the root element of DOM. Equivalent to FirstChildElement(). |
1812 | | To get the first node, use FirstChild(). |
1813 | | */ |
1814 | 0 | XMLElement* RootElement() { |
1815 | 0 | return FirstChildElement(); |
1816 | 0 | } |
1817 | 0 | const XMLElement* RootElement() const { |
1818 | 0 | return FirstChildElement(); |
1819 | 0 | } |
1820 | | |
1821 | | /** Print the Document. If the Printer is not provided, it will |
1822 | | print to stdout. If you provide Printer, this can print to a file: |
1823 | | @verbatim |
1824 | | XMLPrinter printer( fp ); |
1825 | | doc.Print( &printer ); |
1826 | | @endverbatim |
1827 | | |
1828 | | Or you can use a printer to print to memory: |
1829 | | @verbatim |
1830 | | XMLPrinter printer; |
1831 | | doc.Print( &printer ); |
1832 | | // printer.CStr() has a const char* to the XML |
1833 | | @endverbatim |
1834 | | */ |
1835 | | void Print( XMLPrinter* streamer=0 ) const; |
1836 | | virtual bool Accept( XMLVisitor* visitor ) const override; |
1837 | | |
1838 | | /** |
1839 | | Create a new Element associated with |
1840 | | this Document. The memory for the Element |
1841 | | is managed by the Document. |
1842 | | */ |
1843 | | XMLElement* NewElement( const char* name ); |
1844 | | /** |
1845 | | Create a new Comment associated with |
1846 | | this Document. The memory for the Comment |
1847 | | is managed by the Document. |
1848 | | */ |
1849 | | XMLComment* NewComment( const char* comment ); |
1850 | | /** |
1851 | | Create a new Text associated with |
1852 | | this Document. The memory for the Text |
1853 | | is managed by the Document. |
1854 | | */ |
1855 | | XMLText* NewText( const char* text ); |
1856 | | /** |
1857 | | Create a new Declaration associated with |
1858 | | this Document. The memory for the object |
1859 | | is managed by the Document. |
1860 | | |
1861 | | If the 'text' param is null, the standard |
1862 | | declaration is used.: |
1863 | | @verbatim |
1864 | | <?xml version="1.0" encoding="UTF-8"?> |
1865 | | @endverbatim |
1866 | | */ |
1867 | | XMLDeclaration* NewDeclaration( const char* text=0 ); |
1868 | | /** |
1869 | | Create a new Unknown associated with |
1870 | | this Document. The memory for the object |
1871 | | is managed by the Document. |
1872 | | */ |
1873 | | XMLUnknown* NewUnknown( const char* text ); |
1874 | | |
1875 | | /** |
1876 | | Delete a node associated with this document. |
1877 | | It will be unlinked from the DOM. |
1878 | | */ |
1879 | | void DeleteNode( XMLNode* node ); |
1880 | | |
1881 | | /// Clears the error flags. |
1882 | | void ClearError(); |
1883 | | |
1884 | | /// Return true if there was an error parsing the document. |
1885 | 0 | bool Error() const { |
1886 | 0 | return _errorID != XML_SUCCESS; |
1887 | 0 | } |
1888 | | /// Return the errorID. |
1889 | 0 | XMLError ErrorID() const { |
1890 | 0 | return _errorID; |
1891 | 0 | } |
1892 | | const char* ErrorName() const; |
1893 | | static const char* ErrorIDToName(XMLError errorID); |
1894 | | |
1895 | | /** Returns a "long form" error description. A hopefully helpful |
1896 | | diagnostic with location, line number, and/or additional info. |
1897 | | */ |
1898 | | const char* ErrorStr() const; |
1899 | | |
1900 | | /// A (trivial) utility function that prints the ErrorStr() to stdout. |
1901 | | void PrintError() const; |
1902 | | |
1903 | | /// Return the line where the error occurred, or zero if unknown. |
1904 | | int ErrorLineNum() const |
1905 | 0 | { |
1906 | 0 | return _errorLineNum; |
1907 | 0 | } |
1908 | | |
1909 | | /// Clear the document, resetting it to the initial state. |
1910 | | void Clear(); |
1911 | | |
1912 | | /** |
1913 | | Copies this document to a target document. |
1914 | | The target will be completely cleared before the copy. |
1915 | | If you want to copy a sub-tree, see XMLNode::DeepClone(). |
1916 | | |
1917 | | NOTE: that the 'target' must be non-null. |
1918 | | */ |
1919 | | void DeepCopy(XMLDocument* target) const; |
1920 | | |
1921 | | // internal |
1922 | | char* Identify( char* p, XMLNode** node, bool first ); |
1923 | | |
1924 | | // internal |
1925 | | void MarkInUse(const XMLNode* const); |
1926 | | |
1927 | 0 | virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{ |
1928 | 0 | return 0; |
1929 | 0 | } |
1930 | 0 | virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{ |
1931 | 0 | return false; |
1932 | 0 | } |
1933 | | |
1934 | | private: |
1935 | | XMLDocument( const XMLDocument& ); // not supported |
1936 | | void operator=( const XMLDocument& ); // not supported |
1937 | | |
1938 | | bool _writeBOM; |
1939 | | bool _processEntities; |
1940 | | XMLError _errorID; |
1941 | | Whitespace _whitespaceMode; |
1942 | | mutable StrPair _errorStr; |
1943 | | int _errorLineNum; |
1944 | | char* _charBuffer; |
1945 | | int _parseCurLineNum; |
1946 | | int _parsingDepth; |
1947 | | // Memory tracking does add some overhead. |
1948 | | // However, the code assumes that you don't |
1949 | | // have a bunch of unlinked nodes around. |
1950 | | // Therefore it takes less memory to track |
1951 | | // in the document vs. a linked list in the XMLNode, |
1952 | | // and the performance is the same. |
1953 | | DynArray<XMLNode*, 10> _unlinked; |
1954 | | |
1955 | | MemPoolT< sizeof(XMLElement) > _elementPool; |
1956 | | MemPoolT< sizeof(XMLAttribute) > _attributePool; |
1957 | | MemPoolT< sizeof(XMLText) > _textPool; |
1958 | | MemPoolT< sizeof(XMLComment) > _commentPool; |
1959 | | |
1960 | | static const char* _errorNames[XML_ERROR_COUNT]; |
1961 | | |
1962 | | void Parse(); |
1963 | | |
1964 | | void SetError( XMLError error, int lineNum, const char* format, ... ); |
1965 | | |
1966 | | // Something of an obvious security hole, once it was discovered. |
1967 | | // Either an ill-formed XML or an excessively deep one can overflow |
1968 | | // the stack. Track stack depth, and error out if needed. |
1969 | | class DepthTracker { |
1970 | | public: |
1971 | 0 | explicit DepthTracker(XMLDocument * document) { |
1972 | 0 | this->_document = document; |
1973 | 0 | document->PushDepth(); |
1974 | 0 | } |
1975 | 0 | ~DepthTracker() { |
1976 | 0 | _document->PopDepth(); |
1977 | 0 | } |
1978 | | private: |
1979 | | XMLDocument * _document; |
1980 | | }; |
1981 | | void PushDepth(); |
1982 | | void PopDepth(); |
1983 | | |
1984 | | template<class NodeType, int PoolElementSize> |
1985 | | NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool ); |
1986 | | }; |
1987 | | |
1988 | | template<class NodeType, int PoolElementSize> |
1989 | | inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool ) |
1990 | 0 | { |
1991 | 0 | TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); |
1992 | 0 | TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); |
1993 | 0 | NodeType* returnNode = new (pool.Alloc()) NodeType( this ); |
1994 | 0 | TIXMLASSERT( returnNode ); |
1995 | 0 | returnNode->_memPool = &pool; |
1996 | |
|
1997 | 0 | _unlinked.Push(returnNode); |
1998 | 0 | return returnNode; |
1999 | 0 | } Unexecuted instantiation: tinyxml2::XMLDeclaration* tinyxml2::XMLDocument::CreateUnlinkedNode<tinyxml2::XMLDeclaration, 104>(tinyxml2::MemPoolT<104>&) Unexecuted instantiation: tinyxml2::XMLComment* tinyxml2::XMLDocument::CreateUnlinkedNode<tinyxml2::XMLComment, 104>(tinyxml2::MemPoolT<104>&) Unexecuted instantiation: tinyxml2::XMLText* tinyxml2::XMLDocument::CreateUnlinkedNode<tinyxml2::XMLText, 112>(tinyxml2::MemPoolT<112>&) Unexecuted instantiation: tinyxml2::XMLUnknown* tinyxml2::XMLDocument::CreateUnlinkedNode<tinyxml2::XMLUnknown, 104>(tinyxml2::MemPoolT<104>&) Unexecuted instantiation: tinyxml2::XMLElement* tinyxml2::XMLDocument::CreateUnlinkedNode<tinyxml2::XMLElement, 120>(tinyxml2::MemPoolT<120>&) |
2000 | | |
2001 | | /** |
2002 | | A XMLHandle is a class that wraps a node pointer with null checks; this is |
2003 | | an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 |
2004 | | DOM structure. It is a separate utility class. |
2005 | | |
2006 | | Take an example: |
2007 | | @verbatim |
2008 | | <Document> |
2009 | | <Element attributeA = "valueA"> |
2010 | | <Child attributeB = "value1" /> |
2011 | | <Child attributeB = "value2" /> |
2012 | | </Element> |
2013 | | </Document> |
2014 | | @endverbatim |
2015 | | |
2016 | | Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very |
2017 | | easy to write a *lot* of code that looks like: |
2018 | | |
2019 | | @verbatim |
2020 | | XMLElement* root = document.FirstChildElement( "Document" ); |
2021 | | if ( root ) |
2022 | | { |
2023 | | XMLElement* element = root->FirstChildElement( "Element" ); |
2024 | | if ( element ) |
2025 | | { |
2026 | | XMLElement* child = element->FirstChildElement( "Child" ); |
2027 | | if ( child ) |
2028 | | { |
2029 | | XMLElement* child2 = child->NextSiblingElement( "Child" ); |
2030 | | if ( child2 ) |
2031 | | { |
2032 | | // Finally do something useful. |
2033 | | @endverbatim |
2034 | | |
2035 | | And that doesn't even cover "else" cases. XMLHandle addresses the verbosity |
2036 | | of such code. A XMLHandle checks for null pointers so it is perfectly safe |
2037 | | and correct to use: |
2038 | | |
2039 | | @verbatim |
2040 | | XMLHandle docHandle( &document ); |
2041 | | XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); |
2042 | | if ( child2 ) |
2043 | | { |
2044 | | // do something useful |
2045 | | @endverbatim |
2046 | | |
2047 | | Which is MUCH more concise and useful. |
2048 | | |
2049 | | It is also safe to copy handles - internally they are nothing more than node pointers. |
2050 | | @verbatim |
2051 | | XMLHandle handleCopy = handle; |
2052 | | @endverbatim |
2053 | | |
2054 | | See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. |
2055 | | */ |
2056 | | class TINYXML2_LIB XMLHandle |
2057 | | { |
2058 | | public: |
2059 | | /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. |
2060 | 0 | explicit XMLHandle( XMLNode* node ) : _node( node ) { |
2061 | 0 | } |
2062 | | /// Create a handle from a node. |
2063 | 0 | explicit XMLHandle( XMLNode& node ) : _node( &node ) { |
2064 | 0 | } |
2065 | | /// Copy constructor |
2066 | 0 | XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { |
2067 | 0 | } |
2068 | | /// Assignment |
2069 | 0 | XMLHandle& operator=( const XMLHandle& ref ) { |
2070 | 0 | _node = ref._node; |
2071 | 0 | return *this; |
2072 | 0 | } |
2073 | | |
2074 | | /// Get the first child of this handle. |
2075 | 0 | XMLHandle FirstChild() { |
2076 | 0 | return XMLHandle( _node ? _node->FirstChild() : 0 ); |
2077 | 0 | } |
2078 | | /// Get the first child element of this handle. |
2079 | 0 | XMLHandle FirstChildElement( const char* name = 0 ) { |
2080 | 0 | return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); |
2081 | 0 | } |
2082 | | /// Get the last child of this handle. |
2083 | 0 | XMLHandle LastChild() { |
2084 | 0 | return XMLHandle( _node ? _node->LastChild() : 0 ); |
2085 | 0 | } |
2086 | | /// Get the last child element of this handle. |
2087 | 0 | XMLHandle LastChildElement( const char* name = 0 ) { |
2088 | 0 | return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); |
2089 | 0 | } |
2090 | | /// Get the previous sibling of this handle. |
2091 | 0 | XMLHandle PreviousSibling() { |
2092 | 0 | return XMLHandle( _node ? _node->PreviousSibling() : 0 ); |
2093 | 0 | } |
2094 | | /// Get the previous sibling element of this handle. |
2095 | 0 | XMLHandle PreviousSiblingElement( const char* name = 0 ) { |
2096 | 0 | return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); |
2097 | 0 | } |
2098 | | /// Get the next sibling of this handle. |
2099 | 0 | XMLHandle NextSibling() { |
2100 | 0 | return XMLHandle( _node ? _node->NextSibling() : 0 ); |
2101 | 0 | } |
2102 | | /// Get the next sibling element of this handle. |
2103 | 0 | XMLHandle NextSiblingElement( const char* name = 0 ) { |
2104 | 0 | return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); |
2105 | 0 | } |
2106 | | |
2107 | | /// Safe cast to XMLNode. This can return null. |
2108 | 0 | XMLNode* ToNode() { |
2109 | 0 | return _node; |
2110 | 0 | } |
2111 | | /// Safe cast to XMLElement. This can return null. |
2112 | 0 | XMLElement* ToElement() { |
2113 | 0 | return ( _node ? _node->ToElement() : 0 ); |
2114 | 0 | } |
2115 | | /// Safe cast to XMLText. This can return null. |
2116 | 0 | XMLText* ToText() { |
2117 | 0 | return ( _node ? _node->ToText() : 0 ); |
2118 | 0 | } |
2119 | | /// Safe cast to XMLUnknown. This can return null. |
2120 | 0 | XMLUnknown* ToUnknown() { |
2121 | 0 | return ( _node ? _node->ToUnknown() : 0 ); |
2122 | 0 | } |
2123 | | /// Safe cast to XMLDeclaration. This can return null. |
2124 | 0 | XMLDeclaration* ToDeclaration() { |
2125 | 0 | return ( _node ? _node->ToDeclaration() : 0 ); |
2126 | 0 | } |
2127 | | |
2128 | | private: |
2129 | | XMLNode* _node; |
2130 | | }; |
2131 | | |
2132 | | |
2133 | | /** |
2134 | | A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the |
2135 | | same in all regards, except for the 'const' qualifiers. See XMLHandle for API. |
2136 | | */ |
2137 | | class TINYXML2_LIB XMLConstHandle |
2138 | | { |
2139 | | public: |
2140 | 0 | explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { |
2141 | 0 | } |
2142 | 0 | explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { |
2143 | 0 | } |
2144 | 0 | XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { |
2145 | 0 | } |
2146 | | |
2147 | 0 | XMLConstHandle& operator=( const XMLConstHandle& ref ) { |
2148 | 0 | _node = ref._node; |
2149 | 0 | return *this; |
2150 | 0 | } |
2151 | | |
2152 | 0 | const XMLConstHandle FirstChild() const { |
2153 | 0 | return XMLConstHandle( _node ? _node->FirstChild() : 0 ); |
2154 | 0 | } |
2155 | 0 | const XMLConstHandle FirstChildElement( const char* name = 0 ) const { |
2156 | 0 | return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); |
2157 | 0 | } |
2158 | 0 | const XMLConstHandle LastChild() const { |
2159 | 0 | return XMLConstHandle( _node ? _node->LastChild() : 0 ); |
2160 | 0 | } |
2161 | 0 | const XMLConstHandle LastChildElement( const char* name = 0 ) const { |
2162 | 0 | return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); |
2163 | 0 | } |
2164 | 0 | const XMLConstHandle PreviousSibling() const { |
2165 | 0 | return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); |
2166 | 0 | } |
2167 | 0 | const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { |
2168 | 0 | return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); |
2169 | 0 | } |
2170 | 0 | const XMLConstHandle NextSibling() const { |
2171 | 0 | return XMLConstHandle( _node ? _node->NextSibling() : 0 ); |
2172 | 0 | } |
2173 | 0 | const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { |
2174 | 0 | return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); |
2175 | 0 | } |
2176 | | |
2177 | | |
2178 | 0 | const XMLNode* ToNode() const { |
2179 | 0 | return _node; |
2180 | 0 | } |
2181 | 0 | const XMLElement* ToElement() const { |
2182 | 0 | return ( _node ? _node->ToElement() : 0 ); |
2183 | 0 | } |
2184 | 0 | const XMLText* ToText() const { |
2185 | 0 | return ( _node ? _node->ToText() : 0 ); |
2186 | 0 | } |
2187 | 0 | const XMLUnknown* ToUnknown() const { |
2188 | 0 | return ( _node ? _node->ToUnknown() : 0 ); |
2189 | 0 | } |
2190 | 0 | const XMLDeclaration* ToDeclaration() const { |
2191 | 0 | return ( _node ? _node->ToDeclaration() : 0 ); |
2192 | 0 | } |
2193 | | |
2194 | | private: |
2195 | | const XMLNode* _node; |
2196 | | }; |
2197 | | |
2198 | | |
2199 | | /** |
2200 | | Printing functionality. The XMLPrinter gives you more |
2201 | | options than the XMLDocument::Print() method. |
2202 | | |
2203 | | It can: |
2204 | | -# Print to memory. |
2205 | | -# Print to a file you provide. |
2206 | | -# Print XML without a XMLDocument. |
2207 | | |
2208 | | Print to Memory |
2209 | | |
2210 | | @verbatim |
2211 | | XMLPrinter printer; |
2212 | | doc.Print( &printer ); |
2213 | | SomeFunction( printer.CStr() ); |
2214 | | @endverbatim |
2215 | | |
2216 | | Print to a File |
2217 | | |
2218 | | You provide the file pointer. |
2219 | | @verbatim |
2220 | | XMLPrinter printer( fp ); |
2221 | | doc.Print( &printer ); |
2222 | | @endverbatim |
2223 | | |
2224 | | Print without a XMLDocument |
2225 | | |
2226 | | When loading, an XML parser is very useful. However, sometimes |
2227 | | when saving, it just gets in the way. The code is often set up |
2228 | | for streaming, and constructing the DOM is just overhead. |
2229 | | |
2230 | | The Printer supports the streaming case. The following code |
2231 | | prints out a trivially simple XML file without ever creating |
2232 | | an XML document. |
2233 | | |
2234 | | @verbatim |
2235 | | XMLPrinter printer( fp ); |
2236 | | printer.OpenElement( "foo" ); |
2237 | | printer.PushAttribute( "foo", "bar" ); |
2238 | | printer.CloseElement(); |
2239 | | @endverbatim |
2240 | | */ |
2241 | | class TINYXML2_LIB XMLPrinter : public XMLVisitor |
2242 | | { |
2243 | | public: |
2244 | | /** Construct the printer. If the FILE* is specified, |
2245 | | this will print to the FILE. Else it will print |
2246 | | to memory, and the result is available in CStr(). |
2247 | | If 'compact' is set to true, then output is created |
2248 | | with only required whitespace and newlines. |
2249 | | */ |
2250 | | XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); |
2251 | 0 | virtual ~XMLPrinter() {} |
2252 | | |
2253 | | /** If streaming, write the BOM and declaration. */ |
2254 | | void PushHeader( bool writeBOM, bool writeDeclaration ); |
2255 | | /** If streaming, start writing an element. |
2256 | | The element must be closed with CloseElement() |
2257 | | */ |
2258 | | void OpenElement( const char* name, bool compactMode=false ); |
2259 | | /// If streaming, add an attribute to an open element. |
2260 | | void PushAttribute( const char* name, const char* value ); |
2261 | | void PushAttribute( const char* name, int value ); |
2262 | | void PushAttribute( const char* name, unsigned value ); |
2263 | | void PushAttribute( const char* name, int64_t value ); |
2264 | | void PushAttribute( const char* name, uint64_t value ); |
2265 | | void PushAttribute( const char* name, bool value ); |
2266 | | void PushAttribute( const char* name, double value ); |
2267 | | /// If streaming, close the Element. |
2268 | | virtual void CloseElement( bool compactMode=false ); |
2269 | | |
2270 | | /// Add a text node. |
2271 | | void PushText( const char* text, bool cdata=false ); |
2272 | | /// Add a text node from an integer. |
2273 | | void PushText( int value ); |
2274 | | /// Add a text node from an unsigned. |
2275 | | void PushText( unsigned value ); |
2276 | | /// Add a text node from a signed 64bit integer. |
2277 | | void PushText( int64_t value ); |
2278 | | /// Add a text node from an unsigned 64bit integer. |
2279 | | void PushText( uint64_t value ); |
2280 | | /// Add a text node from a bool. |
2281 | | void PushText( bool value ); |
2282 | | /// Add a text node from a float. |
2283 | | void PushText( float value ); |
2284 | | /// Add a text node from a double. |
2285 | | void PushText( double value ); |
2286 | | |
2287 | | /// Add a comment |
2288 | | void PushComment( const char* comment ); |
2289 | | |
2290 | | void PushDeclaration( const char* value ); |
2291 | | void PushUnknown( const char* value ); |
2292 | | |
2293 | | virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override; |
2294 | 0 | virtual bool VisitExit( const XMLDocument& /*doc*/ ) override { |
2295 | 0 | return true; |
2296 | 0 | } |
2297 | | |
2298 | | virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override; |
2299 | | virtual bool VisitExit( const XMLElement& element ) override; |
2300 | | |
2301 | | virtual bool Visit( const XMLText& text ) override; |
2302 | | virtual bool Visit( const XMLComment& comment ) override; |
2303 | | virtual bool Visit( const XMLDeclaration& declaration ) override; |
2304 | | virtual bool Visit( const XMLUnknown& unknown ) override; |
2305 | | |
2306 | | /** |
2307 | | If in print to memory mode, return a pointer to |
2308 | | the XML file in memory. |
2309 | | */ |
2310 | 0 | const char* CStr() const { |
2311 | 0 | return _buffer.Mem(); |
2312 | 0 | } |
2313 | | /** |
2314 | | If in print to memory mode, return the size |
2315 | | of the XML file in memory. (Note the size returned |
2316 | | includes the terminating null.) |
2317 | | */ |
2318 | 0 | int CStrSize() const { |
2319 | 0 | return _buffer.Size(); |
2320 | 0 | } |
2321 | | /** |
2322 | | If in print to memory mode, reset the buffer to the |
2323 | | beginning. |
2324 | | */ |
2325 | 0 | void ClearBuffer( bool resetToFirstElement = true ) { |
2326 | 0 | _buffer.Clear(); |
2327 | 0 | _buffer.Push(0); |
2328 | 0 | _firstElement = resetToFirstElement; |
2329 | 0 | } |
2330 | | |
2331 | | protected: |
2332 | 0 | virtual bool CompactMode( const XMLElement& ) { return _compactMode; } |
2333 | | |
2334 | | /** Prints out the space before an element. You may override to change |
2335 | | the space and tabs used. A PrintSpace() override should call Print(). |
2336 | | */ |
2337 | | virtual void PrintSpace( int depth ); |
2338 | | virtual void Print( const char* format, ... ); |
2339 | | virtual void Write( const char* data, size_t size ); |
2340 | | virtual void Putc( char ch ); |
2341 | | |
2342 | 0 | inline void Write(const char* data) { Write(data, strlen(data)); } |
2343 | | |
2344 | | void SealElementIfJustOpened(); |
2345 | | bool _elementJustOpened; |
2346 | | DynArray< const char*, 10 > _stack; |
2347 | | |
2348 | | private: |
2349 | | /** |
2350 | | Prepares to write a new node. This includes sealing an element that was |
2351 | | just opened, and writing any whitespace necessary if not in compact mode. |
2352 | | */ |
2353 | | void PrepareForNewNode( bool compactMode ); |
2354 | | void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. |
2355 | | |
2356 | | bool _firstElement; |
2357 | | FILE* _fp; |
2358 | | int _depth; |
2359 | | int _textDepth; |
2360 | | bool _processEntities; |
2361 | | bool _compactMode; |
2362 | | |
2363 | | enum { |
2364 | | ENTITY_RANGE = 64, |
2365 | | BUF_SIZE = 200 |
2366 | | }; |
2367 | | bool _entityFlag[ENTITY_RANGE]; |
2368 | | bool _restrictedEntityFlag[ENTITY_RANGE]; |
2369 | | |
2370 | | DynArray< char, 20 > _buffer; |
2371 | | |
2372 | | // Prohibit cloning, intentionally not implemented |
2373 | | XMLPrinter( const XMLPrinter& ); |
2374 | | XMLPrinter& operator=( const XMLPrinter& ); |
2375 | | }; |
2376 | | |
2377 | | |
2378 | | } // tinyxml2 |
2379 | | |
2380 | | #if defined(_MSC_VER) |
2381 | | # pragma warning(pop) |
2382 | | #endif |
2383 | | |
2384 | | #endif // TINYXML2_INCLUDED |