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