Coverage Report

Created: 2025-07-12 06:10

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