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