blob: 452ae95bbcc8f47bef3b9350e893408855f7a061 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
Lee Thomason7d00b9a2012-02-27 17:54:22 -080024#ifndef TINYXML2_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025#define TINYXML2_INCLUDED
26
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <ctype.h>
29# include <limits.h>
30# include <stdio.h>
31# include <stdlib.h>
32# include <string.h>
Lee Thomasona572db12016-06-04 19:16:24 -070033# if defined(__PS3__)
34# include <stddef.h>
35# endif
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070036#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070037# include <cctype>
38# include <climits>
39# include <cstdio>
40# include <cstdlib>
41# include <cstring>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070042#endif
Lee Thomason1889c3e2016-06-04 20:22:57 -070043#include <stdint.h>
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070044
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070045/*
Lee Thomason7d00b9a2012-02-27 17:54:22 -080046 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080047*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080048/*
Lee Thomasona9cf3f92012-10-11 16:56:51 -070049 gcc:
Peter Matula50689912018-01-09 12:52:26 +010050 g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
MortenMacFly4ee49f12013-01-14 20:03:14 +010051
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 Formatting, Artistic Style:
53 AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080054*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080055
Lee Thomason7085f002017-06-01 18:09:43 -070056#if defined( _DEBUG ) || defined (__DEBUG__)
Peter Matula50689912018-01-09 12:52:26 +010057# ifndef TINYXML2_DEBUG
58# define TINYXML2_DEBUG
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059# endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080060#endif
61
PKEuS95060352013-07-26 10:42:44 +020062#ifdef _MSC_VER
63# pragma warning(push)
64# pragma warning(disable: 4251)
65#endif
U-Lama\Lee4cee6112011-12-31 14:58:18 -080066
PKEuS16ed47d2013-07-06 12:02:43 +020067#ifdef _WIN32
68# ifdef TINYXML2_EXPORT
69# define TINYXML2_LIB __declspec(dllexport)
70# elif defined(TINYXML2_IMPORT)
71# define TINYXML2_LIB __declspec(dllimport)
72# else
73# define TINYXML2_LIB
74# endif
Matthew Woehlkea8e7ea72016-08-09 13:16:26 -040075#elif __GNUC__ >= 4
76# define TINYXML2_LIB __attribute__((visibility("default")))
PKEuS16ed47d2013-07-06 12:02:43 +020077#else
78# define TINYXML2_LIB
79#endif
80
81
Pantelis Lekakis6df0cae2020-09-08 00:40:44 +010082#if !defined(TIXMLASSERT)
Peter Matula50689912018-01-09 12:52:26 +010083#if defined(TINYXML2_DEBUG)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070084# if defined(_MSC_VER)
Dmitry-Me4bcbf142014-12-25 19:05:18 +030085# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
Lee Thomason598a88d2015-10-09 14:42:12 -070086# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
Lee Thomasona9cf3f92012-10-11 16:56:51 -070087# elif defined (ANDROID_NDK)
88# include <android/log.h>
89# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
90# else
91# include <assert.h>
92# define TIXMLASSERT assert
93# endif
Lee Thomason598a88d2015-10-09 14:42:12 -070094#else
95# define TIXMLASSERT( x ) {}
U-Lama\Lee4cee6112011-12-31 14:58:18 -080096#endif
Pantelis Lekakis6df0cae2020-09-08 00:40:44 +010097#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -080098
Lee Thomasonc18eb232014-02-21 17:31:17 -080099/* Versioning, past 1.0.14:
Lee Thomason85afe9c2014-02-23 21:42:16 -0800100 http://semver.org/
Lee Thomasonc18eb232014-02-21 17:31:17 -0800101*/
Lee Thomason1dee28e2021-06-06 17:10:24 -0700102static const int TIXML2_MAJOR_VERSION = 9;
103static const int TIXML2_MINOR_VERSION = 0;
Lee Thomason9c740e82019-08-10 18:05:22 -0700104static const int TIXML2_PATCH_VERSION = 0;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800105
Lee Thomason1dee28e2021-06-06 17:10:24 -0700106#define TINYXML2_MAJOR_VERSION 9
107#define TINYXML2_MINOR_VERSION 0
Lee Thomason9c740e82019-08-10 18:05:22 -0700108#define TINYXML2_PATCH_VERSION 0
Lee Thomasonbd197872017-12-28 13:31:48 -0800109
Lee Thomason70d942e2018-06-29 15:31:59 -0700110// A fixed element depth limit is problematic. There needs to be a
111// limit to avoid a stack overflow. However, that limit varies per
112// system, and the capacity of the stack. On the other hand, it's a trivial
113// attack that can result from ill, malicious, or even correctly formed XML,
Lee Thomasonf928c352018-04-05 09:24:20 -0700114// so there needs to be a limit in place.
115static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
Lee Thomasond946dda2018-04-05 09:11:08 -0700116
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800117namespace tinyxml2
118{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800119class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800120class XMLElement;
121class XMLAttribute;
122class XMLComment;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800123class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800124class XMLDeclaration;
125class XMLUnknown;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800126class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800127
U-Stream\Leeae25a442012-02-17 17:48:16 -0800128/*
129 A class that wraps strings. Normally stores the start and end
130 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800131 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800132 manage) a traditional char[]
Lee Thomasonde6d1642018-11-17 19:53:46 -0800133
134 Isn't clear why TINYXML2_LIB is needed; but seems to fix #719
U-Stream\Leeae25a442012-02-17 17:48:16 -0800135*/
Lee Thomasonde6d1642018-11-17 19:53:46 -0800136class TINYXML2_LIB StrPair
Lee Thomason39ede242012-01-20 11:27:56 -0800137{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800138public:
Pantelis Lekakisc87bf812020-09-23 21:59:13 +0100139 enum Mode {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 NEEDS_ENTITY_PROCESSING = 0x01,
141 NEEDS_NEWLINE_NORMALIZATION = 0x02,
Dmitry-Me5420e542015-05-20 10:51:26 +0300142 NEEDS_WHITESPACE_COLLAPSING = 0x04,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800143
Lee Thomason584af572016-09-05 14:14:16 -0700144 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700145 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason584af572016-09-05 14:14:16 -0700146 ATTRIBUTE_NAME = 0,
147 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
148 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
149 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 };
Lee Thomason39ede242012-01-20 11:27:56 -0800151
Lee Thomason120b3a62012-10-12 10:06:59 -0700152 StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 ~StrPair();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800154
Lee Thomason120b3a62012-10-12 10:06:59 -0700155 void Set( char* start, char* end, int flags ) {
Dmitry-Me6fc38ec2016-09-01 17:59:44 +0300156 TIXMLASSERT( start );
157 TIXMLASSERT( end );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700158 Reset();
Lee Thomason120b3a62012-10-12 10:06:59 -0700159 _start = start;
160 _end = end;
161 _flags = flags | NEEDS_FLUSH;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700163
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700164 const char* GetStr();
Lee Thomason120b3a62012-10-12 10:06:59 -0700165
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700166 bool Empty() const {
Lee Thomason120b3a62012-10-12 10:06:59 -0700167 return _start == _end;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700168 }
Lee Thomason39ede242012-01-20 11:27:56 -0800169
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700170 void SetInternedStr( const char* str ) {
171 Reset();
Lee Thomason120b3a62012-10-12 10:06:59 -0700172 _start = const_cast<char*>(str);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700175 void SetStr( const char* str, int flags=0 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176
kezenator4f756162016-11-29 19:46:27 +1000177 char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700178 char* ParseName( char* in );
Lee Thomason56bdd022012-02-09 18:16:58 -0800179
Lee Thomason29658802014-11-27 22:31:11 -0800180 void TransferTo( StrPair* other );
Lee Thomason584af572016-09-05 14:14:16 -0700181 void Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300182
Lee Thomason39ede242012-01-20 11:27:56 -0800183private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700184 void CollapseWhitespace();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800185
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700186 enum {
187 NEEDS_FLUSH = 0x100,
188 NEEDS_DELETE = 0x200
189 };
Lee Thomasone4422302012-01-20 17:59:50 -0800190
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 int _flags;
192 char* _start;
193 char* _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300194
195 StrPair( const StrPair& other ); // not supported
Bo Rydberg65c1b862018-10-19 18:45:53 +0200196 void operator=( const StrPair& other ); // not supported, use TransferTo()
Lee Thomason39ede242012-01-20 11:27:56 -0800197};
198
U-Lama\Lee560bd472011-12-28 19:42:49 -0800199
U-Stream\Leeae25a442012-02-17 17:48:16 -0800200/*
201 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
202 Has a small initial memory pool, so that low or no usage will not
203 cause a call to new/delete
204*/
Dmitry-Me04009222015-04-06 18:07:18 +0300205template <class T, int INITIAL_SIZE>
PKEuS95060352013-07-26 10:42:44 +0200206class DynArray
Lee Thomason2c85a712012-01-31 08:24:24 -0800207{
208public:
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200209 DynArray() :
210 _mem( _pool ),
211 _allocated( INITIAL_SIZE ),
212 _size( 0 )
213 {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700214 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 ~DynArray() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700217 if ( _mem != _pool ) {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700218 delete [] _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700219 }
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221
Lee Thomasonce0510b2013-11-26 21:29:37 -0800222 void Clear() {
Reinhard Klambauer4e74b132013-11-22 14:01:58 +0100223 _size = 0;
224 }
225
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700226 void Push( T t ) {
Dmitry-Meed7a7dc2015-01-14 08:36:12 +0300227 TIXMLASSERT( _size < INT_MAX );
Lee Thomason624d43f2012-10-12 10:58:48 -0700228 EnsureCapacity( _size+1 );
Dmitry-Mefed51122016-09-06 18:08:55 +0300229 _mem[_size] = t;
230 ++_size;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800232
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700233 T* PushArr( int count ) {
Dmitry-Me74fb8702015-01-13 10:27:36 +0300234 TIXMLASSERT( count >= 0 );
Dmitry-Meed7a7dc2015-01-14 08:36:12 +0300235 TIXMLASSERT( _size <= INT_MAX - count );
Lee Thomason624d43f2012-10-12 10:58:48 -0700236 EnsureCapacity( _size+count );
237 T* ret = &_mem[_size];
238 _size += count;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700239 return ret;
240 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700241
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 T Pop() {
Dmitry-Me74fb8702015-01-13 10:27:36 +0300243 TIXMLASSERT( _size > 0 );
Dmitry-Mefed51122016-09-06 18:08:55 +0300244 --_size;
245 return _mem[_size];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700246 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 void PopArr( int count ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700249 TIXMLASSERT( _size >= count );
250 _size -= count;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800252
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700253 bool Empty() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700254 return _size == 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700256
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700257 T& operator[](int i) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700258 TIXMLASSERT( i>= 0 && i < _size );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700259 return _mem[i];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700261
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700262 const T& operator[](int i) const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700263 TIXMLASSERT( i>= 0 && i < _size );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700264 return _mem[i];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700265 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700266
Lee Thomasonf07b9522014-10-30 13:25:12 -0700267 const T& PeekTop() const {
Dennis Jenkins59c75d32013-10-08 13:10:07 -0500268 TIXMLASSERT( _size > 0 );
269 return _mem[ _size - 1];
270 }
271
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700272 int Size() const {
Dmitry-Me30bdc972015-01-14 08:32:23 +0300273 TIXMLASSERT( _size >= 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -0700274 return _size;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700276
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 int Capacity() const {
Dmitry-Me2f5a1032015-06-18 16:40:09 +0300278 TIXMLASSERT( _allocated >= INITIAL_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -0700279 return _allocated;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700281
Lee Thomason816d3fa2017-06-05 14:35:55 -0700282 void SwapRemove(int i) {
Dmitry-Mec2f677b2017-06-15 12:44:27 +0300283 TIXMLASSERT(i >= 0 && i < _size);
284 TIXMLASSERT(_size > 0);
Lee Thomason816d3fa2017-06-05 14:35:55 -0700285 _mem[i] = _mem[_size - 1];
286 --_size;
287 }
288
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700289 const T* Mem() const {
Dmitry-Me2f5a1032015-06-18 16:40:09 +0300290 TIXMLASSERT( _mem );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700291 return _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293
orbitcowboy2cc8a4c2018-09-05 08:46:21 +0200294 T* Mem() {
Dmitry-Me2f5a1032015-06-18 16:40:09 +0300295 TIXMLASSERT( _mem );
Lee Thomasoned5c8792012-10-12 10:09:48 -0700296 return _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700297 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800298
Lee Thomason2c85a712012-01-31 08:24:24 -0800299private:
Dmitry-Me3e0af372015-01-09 15:30:00 +0300300 DynArray( const DynArray& ); // not supported
301 void operator=( const DynArray& ); // not supported
302
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 void EnsureCapacity( int cap ) {
Dmitry-Me9fae8692014-12-22 17:59:59 +0300304 TIXMLASSERT( cap > 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -0700305 if ( cap > _allocated ) {
Dmitry-Me9fae8692014-12-22 17:59:59 +0300306 TIXMLASSERT( cap <= INT_MAX / 2 );
orbitcowboy0e7f2892019-01-15 11:28:49 +0100307 const int newAllocated = cap * 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 T* newMem = new T[newAllocated];
Dmitry-Me243ddf52017-05-18 17:27:14 +0300309 TIXMLASSERT( newAllocated >= _size );
Lee Thomason624d43f2012-10-12 10:58:48 -0700310 memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
311 if ( _mem != _pool ) {
Lee Thomasoned5c8792012-10-12 10:09:48 -0700312 delete [] _mem;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
Lee Thomasoned5c8792012-10-12 10:09:48 -0700314 _mem = newMem;
Lee Thomason624d43f2012-10-12 10:58:48 -0700315 _allocated = newAllocated;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 }
317 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800318
Lee Thomason624d43f2012-10-12 10:58:48 -0700319 T* _mem;
Dmitry-Me04009222015-04-06 18:07:18 +0300320 T _pool[INITIAL_SIZE];
Lee Thomason624d43f2012-10-12 10:58:48 -0700321 int _allocated; // objects allocated
322 int _size; // number objects in use
Lee Thomason2c85a712012-01-31 08:24:24 -0800323};
324
Lee Thomason50adb4c2012-02-13 15:07:09 -0800325
U-Stream\Leeae25a442012-02-17 17:48:16 -0800326/*
Thomas Roß08bdf502012-05-12 14:21:23 +0200327 Parent virtual class of a pool for fast allocation
U-Stream\Leeae25a442012-02-17 17:48:16 -0800328 and deallocation of objects.
329*/
PKEuS95060352013-07-26 10:42:44 +0200330class MemPool
Lee Thomasond1983222012-02-06 08:41:24 -0800331{
332public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 MemPool() {}
334 virtual ~MemPool() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800335
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 virtual int ItemSize() const = 0;
337 virtual void* Alloc() = 0;
338 virtual void Free( void* ) = 0;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800339 virtual void SetTracked() = 0;
Lee Thomasond1983222012-02-06 08:41:24 -0800340};
341
Lee Thomason50adb4c2012-02-13 15:07:09 -0800342
U-Stream\Leeae25a442012-02-17 17:48:16 -0800343/*
344 Template child class to create pools of the correct type.
345*/
Dmitry-Me88145b82016-08-09 17:59:31 +0300346template< int ITEM_SIZE >
PKEuS95060352013-07-26 10:42:44 +0200347class MemPoolT : public MemPool
Lee Thomasond1983222012-02-06 08:41:24 -0800348{
349public:
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200350 MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 ~MemPoolT() {
Lee Thomasonc07409b2018-08-25 11:04:13 -0700352 MemPoolT< ITEM_SIZE >::Clear();
Lee Thomasonf07b9522014-10-30 13:25:12 -0700353 }
Lee Thomason70d942e2018-06-29 15:31:59 -0700354
Lee Thomasonf07b9522014-10-30 13:25:12 -0700355 void Clear() {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 // Delete the blocks.
Lee Thomasonf07b9522014-10-30 13:25:12 -0700357 while( !_blockPtrs.Empty()) {
Dmitry-Meeffab6f2017-07-26 17:57:50 +0300358 Block* lastBlock = _blockPtrs.Pop();
359 delete lastBlock;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 }
Lee Thomasonf07b9522014-10-30 13:25:12 -0700361 _root = 0;
362 _currentAllocs = 0;
363 _nAllocs = 0;
364 _maxAllocs = 0;
365 _nUntracked = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 }
Lee Thomasond1983222012-02-06 08:41:24 -0800367
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 virtual int ItemSize() const {
Dmitry-Me88145b82016-08-09 17:59:31 +0300369 return ITEM_SIZE;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 }
371 int CurrentAllocs() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700372 return _currentAllocs;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 }
Lee Thomasond1983222012-02-06 08:41:24 -0800374
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700375 virtual void* Alloc() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700376 if ( !_root ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 // Need a new block.
378 Block* block = new Block();
Lee Thomason624d43f2012-10-12 10:58:48 -0700379 _blockPtrs.Push( block );
Lee Thomasond1983222012-02-06 08:41:24 -0800380
Dmitry-Me88145b82016-08-09 17:59:31 +0300381 Item* blockItems = block->items;
382 for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
383 blockItems[i].next = &(blockItems[i + 1]);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 }
Dmitry-Me88145b82016-08-09 17:59:31 +0300385 blockItems[ITEMS_PER_BLOCK - 1].next = 0;
386 _root = blockItems;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 }
Dmitry-Me88145b82016-08-09 17:59:31 +0300388 Item* const result = _root;
389 TIXMLASSERT( result != 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -0700390 _root = _root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800391
Lee Thomason624d43f2012-10-12 10:58:48 -0700392 ++_currentAllocs;
393 if ( _currentAllocs > _maxAllocs ) {
394 _maxAllocs = _currentAllocs;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700395 }
Dmitry-Me3161a332016-09-02 16:58:06 +0300396 ++_nAllocs;
397 ++_nUntracked;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return result;
399 }
Lee Thomason70d942e2018-06-29 15:31:59 -0700400
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700401 virtual void Free( void* mem ) {
402 if ( !mem ) {
403 return;
404 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700405 --_currentAllocs;
Dmitry-Me88145b82016-08-09 17:59:31 +0300406 Item* item = static_cast<Item*>( mem );
Peter Matula50689912018-01-09 12:52:26 +0100407#ifdef TINYXML2_DEBUG
Dmitry-Me88145b82016-08-09 17:59:31 +0300408 memset( item, 0xfe, sizeof( *item ) );
Lee Thomason (grinliz)6020a012012-09-08 21:15:09 -0700409#endif
Dmitry-Me88145b82016-08-09 17:59:31 +0300410 item->next = _root;
411 _root = item;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 }
413 void Trace( const char* name ) {
414 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
Dmitry-Me88145b82016-08-09 17:59:31 +0300415 name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
416 ITEM_SIZE, _nAllocs, _blockPtrs.Size() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700417 }
Lee Thomasond1983222012-02-06 08:41:24 -0800418
Lee Thomason5b0a6772012-11-19 13:54:42 -0800419 void SetTracked() {
Dmitry-Me3161a332016-09-02 16:58:06 +0300420 --_nUntracked;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800421 }
422
423 int Untracked() const {
424 return _nUntracked;
425 }
426
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -0800427 // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
428 // The test file is large, 170k.
429 // Release: VS2010 gcc(no opt)
430 // 1k: 4000
431 // 2k: 4000
432 // 4k: 3900 21000
433 // 16k: 5200
434 // 32k: 4300
435 // 64k: 4000 21000
Dmitry-Me88145b82016-08-09 17:59:31 +0300436 // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
437 // in private part if ITEMS_PER_BLOCK is private
438 enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
Jerome Martinez7921df12012-10-24 11:45:44 +0200439
Lee Thomasond1983222012-02-06 08:41:24 -0800440private:
Dmitry-Me3e0af372015-01-09 15:30:00 +0300441 MemPoolT( const MemPoolT& ); // not supported
442 void operator=( const MemPoolT& ); // not supported
443
Dmitry-Me88145b82016-08-09 17:59:31 +0300444 union Item {
445 Item* next;
446 char itemData[ITEM_SIZE];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 };
448 struct Block {
Dmitry-Me88145b82016-08-09 17:59:31 +0300449 Item items[ITEMS_PER_BLOCK];
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 };
Lee Thomason624d43f2012-10-12 10:58:48 -0700451 DynArray< Block*, 10 > _blockPtrs;
Dmitry-Me88145b82016-08-09 17:59:31 +0300452 Item* _root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800453
Lee Thomason624d43f2012-10-12 10:58:48 -0700454 int _currentAllocs;
455 int _nAllocs;
456 int _maxAllocs;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800457 int _nUntracked;
Lee Thomasond1983222012-02-06 08:41:24 -0800458};
459
Lee Thomason2c85a712012-01-31 08:24:24 -0800460
Lee Thomason56bdd022012-02-09 18:16:58 -0800461
462/**
463 Implements the interface to the "Visitor pattern" (see the Accept() method.)
464 If you call the Accept() method, it requires being passed a XMLVisitor
465 class to handle callbacks. For nodes that contain other nodes (Document, Element)
Thomas Roß08bdf502012-05-12 14:21:23 +0200466 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
Lee Thomason56bdd022012-02-09 18:16:58 -0800467 are simply called with Visit().
468
469 If you return 'true' from a Visit method, recursive parsing will continue. If you return
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700470 false, <b>no children of this node or its siblings</b> will be visited.
Lee Thomason56bdd022012-02-09 18:16:58 -0800471
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700472 All flavors of Visit methods have a default implementation that returns 'true' (continue
Lee Thomason56bdd022012-02-09 18:16:58 -0800473 visiting). You need to only override methods that are interesting to you.
474
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600475 Generally Accept() is called on the XMLDocument, although all nodes support visiting.
Lee Thomason56bdd022012-02-09 18:16:58 -0800476
477 You should never change the document from a callback.
478
479 @sa XMLNode::Accept()
480*/
PKEuS16ed47d2013-07-06 12:02:43 +0200481class TINYXML2_LIB XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800482{
483public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800485
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 /// Visit a document.
487 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) {
488 return true;
489 }
490 /// Visit a document.
491 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
492 return true;
493 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800494
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 /// Visit an element.
496 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) {
497 return true;
498 }
499 /// Visit an element.
500 virtual bool VisitExit( const XMLElement& /*element*/ ) {
501 return true;
502 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800503
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 /// Visit a declaration.
505 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) {
506 return true;
507 }
508 /// Visit a text node.
509 virtual bool Visit( const XMLText& /*text*/ ) {
510 return true;
511 }
512 /// Visit a comment node.
513 virtual bool Visit( const XMLComment& /*comment*/ ) {
514 return true;
515 }
516 /// Visit an unknown node.
517 virtual bool Visit( const XMLUnknown& /*unknown*/ ) {
518 return true;
519 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800520};
521
Dmitry-Me66d2a842014-11-08 15:24:52 +0300522// WARNING: must match XMLDocument::_errorNames[]
numatrumpetbb5ffac2014-09-06 22:56:46 +0900523enum XMLError {
numatrumpetcd8550c2014-09-08 16:59:39 +0900524 XML_SUCCESS = 0,
numatrumpetcd8550c2014-09-08 16:59:39 +0900525 XML_NO_ATTRIBUTE,
526 XML_WRONG_ATTRIBUTE_TYPE,
527 XML_ERROR_FILE_NOT_FOUND,
528 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
529 XML_ERROR_FILE_READ_ERROR,
numatrumpetcd8550c2014-09-08 16:59:39 +0900530 XML_ERROR_PARSING_ELEMENT,
531 XML_ERROR_PARSING_ATTRIBUTE,
numatrumpetcd8550c2014-09-08 16:59:39 +0900532 XML_ERROR_PARSING_TEXT,
533 XML_ERROR_PARSING_CDATA,
534 XML_ERROR_PARSING_COMMENT,
535 XML_ERROR_PARSING_DECLARATION,
536 XML_ERROR_PARSING_UNKNOWN,
537 XML_ERROR_EMPTY_DOCUMENT,
538 XML_ERROR_MISMATCHED_ELEMENT,
539 XML_ERROR_PARSING,
540 XML_CAN_NOT_CONVERT_TEXT,
Lee Thomason331596e2014-09-11 14:56:43 -0700541 XML_NO_TEXT_NODE,
Lee Thomasond946dda2018-04-05 09:11:08 -0700542 XML_ELEMENT_DEPTH_EXCEEDED,
Lee Thomason331596e2014-09-11 14:56:43 -0700543
544 XML_ERROR_COUNT
numatrumpetbb5ffac2014-09-06 22:56:46 +0900545};
numatrumpetbb5ffac2014-09-06 22:56:46 +0900546
numatrumpetcd8550c2014-09-08 16:59:39 +0900547
U-Stream\Leeae25a442012-02-17 17:48:16 -0800548/*
549 Utility functionality.
550*/
Lee Thomasonce667c92016-12-26 16:45:30 -0800551class TINYXML2_LIB XMLUtil
Lee Thomason56bdd022012-02-09 18:16:58 -0800552{
Lee Thomasond1983222012-02-06 08:41:24 -0800553public:
kezenator4f756162016-11-29 19:46:27 +1000554 static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300555 TIXMLASSERT( p );
Lee Thomasone90e9012016-12-24 07:34:39 -0800556
Dmitry-Mefa20b222014-10-31 12:53:04 +0300557 while( IsWhiteSpace(*p) ) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800558 if (curLineNumPtr && *p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000559 ++(*curLineNumPtr);
kezenatorec694152016-11-26 17:21:43 +1000560 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 ++p;
562 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300563 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 return p;
565 }
orbitcowboy73f54092019-08-14 09:30:30 +0200566 static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) {
kezenator4f756162016-11-29 19:46:27 +1000567 return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 }
Dmitry-Mefa20b222014-10-31 12:53:04 +0300569
570 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
571 // correct, but simple, and usually works.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 static bool IsWhiteSpace( char p ) {
Jerome Martinez242c3ea2013-01-06 12:20:04 +0100573 return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 }
Lee Thomason70d942e2018-06-29 15:31:59 -0700575
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200576 inline static bool IsNameStartChar( unsigned char ch ) {
Dmitry-Meea617f92015-01-01 16:32:01 +0300577 if ( ch >= 128 ) {
578 // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
579 return true;
580 }
581 if ( isalpha( ch ) ) {
582 return true;
583 }
584 return ch == ':' || ch == '_';
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200585 }
Lee Thomason70d942e2018-06-29 15:31:59 -0700586
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200587 inline static bool IsNameChar( unsigned char ch ) {
588 return IsNameStartChar( ch )
589 || isdigit( ch )
590 || ch == '.'
591 || ch == '-';
592 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800593
netcandfb45cb2020-02-15 21:35:58 +0800594 inline static bool IsPrefixHex( const char* p) {
Lee Thomason18468b82020-06-13 17:35:21 -0700595 p = SkipWhiteSpace(p, 0);
596 return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X');
netcandfb45cb2020-02-15 21:35:58 +0800597 }
598
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700600 if ( p == q ) {
601 return true;
602 }
Dmitry-Me21f99692016-10-03 13:01:57 +0300603 TIXMLASSERT( p );
604 TIXMLASSERT( q );
605 TIXMLASSERT( nChar >= 0 );
Lee Thomason598a88d2015-10-09 14:42:12 -0700606 return strncmp( p, q, nChar ) == 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
Lee Thomason70d942e2018-06-29 15:31:59 -0700608
orbitcowboy73f54092019-08-14 09:30:30 +0200609 inline static bool IsUTF8Continuation( const char p ) {
Dmitry-Me72bb0ec2014-09-24 16:14:24 +0400610 return ( p & 0x80 ) != 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800612
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 static const char* ReadBOM( const char* p, bool* hasBOM );
614 // p is the starting location,
615 // the UTF-8 value of the entity will be placed in value, and length filled in.
616 static const char* GetCharacterRef( const char* p, char* value, int* length );
617 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason21be8822012-07-15 17:27:22 -0700618
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 // converts primitive types to strings
620 static void ToStr( int v, char* buffer, int bufferSize );
621 static void ToStr( unsigned v, char* buffer, int bufferSize );
622 static void ToStr( bool v, char* buffer, int bufferSize );
623 static void ToStr( float v, char* buffer, int bufferSize );
624 static void ToStr( double v, char* buffer, int bufferSize );
Lee Thomason51c12712016-06-04 20:18:49 -0700625 static void ToStr(int64_t v, char* buffer, int bufferSize);
cugone47e229e2019-04-12 17:27:28 -0500626 static void ToStr(uint64_t v, char* buffer, int bufferSize);
Lee Thomason21be8822012-07-15 17:27:22 -0700627
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 // converts strings to primitive types
629 static bool ToInt( const char* str, int* value );
630 static bool ToUnsigned( const char* str, unsigned* value );
631 static bool ToBool( const char* str, bool* value );
632 static bool ToFloat( const char* str, float* value );
633 static bool ToDouble( const char* str, double* value );
Lee Thomason51c12712016-06-04 20:18:49 -0700634 static bool ToInt64(const char* str, int64_t* value);
cugone75a5acc2019-04-11 22:03:43 -0500635 static bool ToUnsigned64(const char* str, uint64_t* value);
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800636 // Changes what is serialized for a boolean value.
637 // Default to "true" and "false". Shouldn't be changed
638 // unless you have a special testing or compatibility need.
Lee Thomasonce667c92016-12-26 16:45:30 -0800639 // Be careful: static, global, & not thread safe.
640 // Be sure to set static const memory as parameters.
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800641 static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
Lee Thomasonce667c92016-12-26 16:45:30 -0800642
643private:
Lee Thomasonf458d262016-12-26 22:47:25 -0800644 static const char* writeBoolTrue;
645 static const char* writeBoolFalse;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800646};
647
Lee Thomason5cae8972012-01-24 18:03:07 -0800648
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800649/** XMLNode is a base class for every object that is in the
650 XML Document Object Model (DOM), except XMLAttributes.
651 Nodes have siblings, a parent, and children which can
652 be navigated. A node is always in a XMLDocument.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700653 The type of a XMLNode can be queried, and it can
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800654 be cast to its more defined type.
655
Thomas Roß08bdf502012-05-12 14:21:23 +0200656 A XMLDocument allocates memory for all its Nodes.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800657 When the XMLDocument gets deleted, all its Nodes
658 will also be deleted.
659
660 @verbatim
661 A Document can contain: Element (container or leaf)
662 Comment (leaf)
663 Unknown (leaf)
664 Declaration( leaf )
665
666 An Element can contain: Element (container or leaf)
667 Text (leaf)
668 Attributes (not on tree)
669 Comment (leaf)
670 Unknown (leaf)
671
672 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800673*/
PKEuS16ed47d2013-07-06 12:02:43 +0200674class TINYXML2_LIB XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 friend class XMLDocument;
677 friend class XMLElement;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800679
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 /// Get the XMLDocument that owns this XMLNode.
681 const XMLDocument* GetDocument() const {
Dmitry-Me66487eb2015-07-20 18:21:04 +0300682 TIXMLASSERT( _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 return _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 }
685 /// Get the XMLDocument that owns this XMLNode.
686 XMLDocument* GetDocument() {
Dmitry-Me66487eb2015-07-20 18:21:04 +0300687 TIXMLASSERT( _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 return _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Lee Thomason2fa81722012-11-09 12:37:46 -0800691 /// Safely cast to an Element, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 virtual XMLElement* ToElement() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100693 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800695 /// Safely cast to Text, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 virtual XMLText* ToText() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100697 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800699 /// Safely cast to a Comment, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 virtual XMLComment* ToComment() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100701 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800703 /// Safely cast to a Document, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 virtual XMLDocument* ToDocument() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100705 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800707 /// Safely cast to a Declaration, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 virtual XMLDeclaration* ToDeclaration() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100709 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 }
Lee Thomason2fa81722012-11-09 12:37:46 -0800711 /// Safely cast to an Unknown, or null.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 virtual XMLUnknown* ToUnknown() {
MortenMacFly4ee49f12013-01-14 20:03:14 +0100713 return 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800715
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 virtual const XMLElement* ToElement() const {
717 return 0;
718 }
719 virtual const XMLText* ToText() const {
720 return 0;
721 }
722 virtual const XMLComment* ToComment() const {
723 return 0;
724 }
725 virtual const XMLDocument* ToDocument() const {
726 return 0;
727 }
728 virtual const XMLDeclaration* ToDeclaration() const {
729 return 0;
730 }
731 virtual const XMLUnknown* ToUnknown() const {
732 return 0;
733 }
Lee Thomason751da522012-02-10 08:50:51 -0800734
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 /** The meaning of 'value' changes for the specific type.
736 @verbatim
Sarat Addepalli9afd1d02015-05-19 12:56:27 +0530737 Document: empty (NULL is returned, not an empty string)
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 Element: name of the element
739 Comment: the comment text
740 Unknown: the tag contents
741 Text: the text string
742 @endverbatim
743 */
Michael Daumling21626882013-10-22 17:03:37 +0200744 const char* Value() const;
MortenMacFly4ee49f12013-01-14 20:03:14 +0100745
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700746 /** Set the Value of an XML node.
747 @sa Value()
748 */
749 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800750
kezenatorec694152016-11-26 17:21:43 +1000751 /// Gets the line number the node is in, if the document was parsed from a file.
kezenator19d8ea82016-11-29 19:50:27 +1000752 int GetLineNum() const { return _parseLineNum; }
kezenatorec694152016-11-26 17:21:43 +1000753
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 /// Get the parent of this node on the DOM.
755 const XMLNode* Parent() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 return _parent;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100758
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 XMLNode* Parent() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 return _parent;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 }
Lee Thomason751da522012-02-10 08:50:51 -0800762
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 /// Returns true if this node has no children.
764 bool NoChildren() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 return !_firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason751da522012-02-10 08:50:51 -0800767
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 /// Get the first child node, or null if none exists.
769 const XMLNode* FirstChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 return _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100772
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 XMLNode* FirstChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 return _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 }
MortenMacFly4ee49f12013-01-14 20:03:14 +0100776
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 /** Get the first child element, or optionally the first child
778 element with the specified name.
779 */
Dmitry-Me886ad972015-07-22 11:00:51 +0300780 const XMLElement* FirstChildElement( const char* name = 0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700781
Dmitry-Me886ad972015-07-22 11:00:51 +0300782 XMLElement* FirstChildElement( const char* name = 0 ) {
783 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 }
Lee Thomason3f57d272012-01-11 15:30:03 -0800785
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 /// Get the last child node, or null if none exists.
787 const XMLNode* LastChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 return _lastChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700789 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700790
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 XMLNode* LastChild() {
Dmitry-Me8d4e0ec2015-03-30 12:58:28 +0300792 return _lastChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason2c85a712012-01-31 08:24:24 -0800794
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 /** Get the last child element or optionally the last child
796 element with the specified name.
797 */
Dmitry-Me886ad972015-07-22 11:00:51 +0300798 const XMLElement* LastChildElement( const char* name = 0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700799
Dmitry-Me886ad972015-07-22 11:00:51 +0300800 XMLElement* LastChildElement( const char* name = 0 ) {
801 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700803
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 /// Get the previous (left) sibling node of this node.
805 const XMLNode* PreviousSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 return _prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700808
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 XMLNode* PreviousSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 return _prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800812
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700813 /// Get the previous (left) sibling element of this node, with an optionally supplied name.
Dmitry-Me886ad972015-07-22 11:00:51 +0300814 const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ;
Lee Thomason624d43f2012-10-12 10:58:48 -0700815
Dmitry-Me886ad972015-07-22 11:00:51 +0300816 XMLElement* PreviousSiblingElement( const char* name = 0 ) {
817 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700819
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 /// Get the next (right) sibling node of this node.
821 const XMLNode* NextSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700824
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 XMLNode* NextSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700828
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700829 /// Get the next (right) sibling element of this node, with an optionally supplied name.
Dmitry-Me886ad972015-07-22 11:00:51 +0300830 const XMLElement* NextSiblingElement( const char* name = 0 ) const;
Lee Thomason624d43f2012-10-12 10:58:48 -0700831
Dmitry-Me886ad972015-07-22 11:00:51 +0300832 XMLElement* NextSiblingElement( const char* name = 0 ) {
833 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 /**
837 Add a child node as the last (right) child.
Michael Daumlinged523282013-10-23 07:47:29 +0200838 If the child node is already part of the document,
839 it is moved from its old location to the new location.
840 Returns the addThis argument or 0 if the node does not
841 belong to the same document.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 */
843 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800844
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700845 XMLNode* LinkEndChild( XMLNode* addThis ) {
846 return InsertEndChild( addThis );
847 }
848 /**
849 Add a child node as the first (left) child.
Michael Daumlinged523282013-10-23 07:47:29 +0200850 If the child node is already part of the document,
851 it is moved from its old location to the new location.
852 Returns the addThis argument or 0 if the node does not
853 belong to the same document.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 */
855 XMLNode* InsertFirstChild( XMLNode* addThis );
856 /**
857 Add a node after the specified child node.
Michael Daumlinged523282013-10-23 07:47:29 +0200858 If the child node is already part of the document,
859 it is moved from its old location to the new location.
860 Returns the addThis argument or 0 if the afterThis node
861 is not a child of this node, or if the node does not
862 belong to the same document.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 */
864 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700865
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 /**
867 Delete all the children of this node.
868 */
869 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800870
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 /**
872 Delete a child of this node.
873 */
874 void DeleteChild( XMLNode* node );
Lee Thomason56bdd022012-02-09 18:16:58 -0800875
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 /**
877 Make a copy of this node, but not its children.
878 You may pass in a Document pointer that will be
879 the owner of the new Node. If the 'document' is
880 null, then the node returned will be allocated
881 from the current Document. (this->GetDocument())
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800882
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 Note: if called on a XMLDocument, this will return null.
884 */
885 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800886
Lee Thomason7085f002017-06-01 18:09:43 -0700887 /**
Lee Thomason1346a172017-06-14 15:14:19 -0700888 Make a copy of this node and all its children.
Lee Thomason7085f002017-06-01 18:09:43 -0700889
Dmitry-Me3f63f212017-06-19 18:25:19 +0300890 If the 'target' is null, then the nodes will
Lee Thomason70d942e2018-06-29 15:31:59 -0700891 be allocated in the current document. If 'target'
892 is specified, the memory will be allocated is the
Lee Thomason1346a172017-06-14 15:14:19 -0700893 specified XMLDocument.
Lee Thomason7085f002017-06-01 18:09:43 -0700894
Lee Thomason70d942e2018-06-29 15:31:59 -0700895 NOTE: This is probably not the correct tool to
Lee Thomason7085f002017-06-01 18:09:43 -0700896 copy a document, since XMLDocuments can have multiple
Lee Thomason1346a172017-06-14 15:14:19 -0700897 top level XMLNodes. You probably want to use
898 XMLDocument::DeepCopy()
Lee Thomason7085f002017-06-01 18:09:43 -0700899 */
Dmitry-Me3f63f212017-06-19 18:25:19 +0300900 XMLNode* DeepClone( XMLDocument* target ) const;
Lee Thomason7085f002017-06-01 18:09:43 -0700901
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 /**
903 Test if 2 nodes are the same, but don't test children.
904 The 2 nodes do not need to be in the same Document.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 Note: if called on a XMLDocument, this will return false.
907 */
908 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600910 /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 XML tree will be conditionally visited and the host will be called back
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600912 via the XMLVisitor interface.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800913
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600914 This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
915 the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 interface versus any other.)
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800917
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 The interface has been based on ideas from:
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800919
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 - http://www.saxproject.org/
921 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800922
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 Which are both good references for "visiting".
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800924
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 An example of using Accept():
926 @verbatim
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600927 XMLPrinter printer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 tinyxmlDoc.Accept( &printer );
929 const char* xmlcstr = printer.CStr();
930 @endverbatim
931 */
932 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800933
Lee Thomason70d942e2018-06-29 15:31:59 -0700934 /**
935 Set user data into the XMLNode. TinyXML-2 in
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700936 no way processes or interprets user data.
937 It is initially 0.
938 */
939 void SetUserData(void* userData) { _userData = userData; }
940
941 /**
942 Get user data set into the XMLNode. TinyXML-2 in
943 no way processes or interprets user data.
944 It is initially 0.
945 */
946 void* GetUserData() const { return _userData; }
947
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800948protected:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +0200949 explicit XMLNode( XMLDocument* );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 virtual ~XMLNode();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700951
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300952 virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
Dmitry-Me9b0f1772015-04-03 10:37:31 +0300953
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 XMLDocument* _document;
955 XMLNode* _parent;
956 mutable StrPair _value;
kezenatorec694152016-11-26 17:21:43 +1000957 int _parseLineNum;
Lee Thomason3f57d272012-01-11 15:30:03 -0800958
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 XMLNode* _firstChild;
960 XMLNode* _lastChild;
Lee Thomason3f57d272012-01-11 15:30:03 -0800961
Lee Thomason624d43f2012-10-12 10:58:48 -0700962 XMLNode* _prev;
963 XMLNode* _next;
Lee Thomason3f57d272012-01-11 15:30:03 -0800964
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700965 void* _userData;
966
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800967private:
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 MemPool* _memPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 void Unlink( XMLNode* child );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400970 static void DeleteNode( XMLNode* node );
Lee Thomason3cebdc42015-01-05 17:16:28 -0800971 void InsertChildPreamble( XMLNode* insertThis ) const;
Dmitry-Meecb9b072016-10-12 16:44:59 +0300972 const XMLElement* ToElementWithName( const char* name ) const;
Dmitry-Mef547a992015-01-09 15:17:09 +0300973
974 XMLNode( const XMLNode& ); // not supported
975 XMLNode& operator=( const XMLNode& ); // not supported
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800976};
977
978
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800979/** XML text.
980
981 Note that a text node can have child element nodes, for example:
982 @verbatim
983 <root>This is <b>bold</b></root>
984 @endverbatim
985
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700986 A text node can have 2 ways to output the next. "normal" output
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800987 and CDATA. It will default to the mode it was parsed from the XML file and
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700988 you generally want to leave it alone, but you can change the output mode with
Vasily Biryukov9a975b72013-05-11 21:41:42 +0600989 SetCData() and query it with CData().
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800990*/
PKEuS16ed47d2013-07-06 12:02:43 +0200991class TINYXML2_LIB XMLText : public XMLNode
Lee Thomason5492a1c2012-01-23 15:32:10 -0800992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800994public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800996
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 virtual XMLText* ToText() {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 return this;
999 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001000 virtual const XMLText* ToText() const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 return this;
1002 }
Lee Thomason5492a1c2012-01-23 15:32:10 -08001003
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 /// Declare whether this should be CDATA or standard text.
Lee Thomason624d43f2012-10-12 10:58:48 -07001005 void SetCData( bool isCData ) {
1006 _isCData = isCData;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 }
1008 /// Returns true if this is a CDATA text element.
1009 bool CData() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001010 return _isCData;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001012
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1014 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001015
Lee Thomason5492a1c2012-01-23 15:32:10 -08001016protected:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02001017 explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 virtual ~XMLText() {}
Lee Thomason5492a1c2012-01-23 15:32:10 -08001019
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001020 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001021
Lee Thomason5492a1c2012-01-23 15:32:10 -08001022private:
Lee Thomason624d43f2012-10-12 10:58:48 -07001023 bool _isCData;
Dmitry-Mef547a992015-01-09 15:17:09 +03001024
1025 XMLText( const XMLText& ); // not supported
1026 XMLText& operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -08001027};
1028
1029
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001030/** An XML Comment. */
PKEuS16ed47d2013-07-06 12:02:43 +02001031class TINYXML2_LIB XMLComment : public XMLNode
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -08001034public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 virtual XMLComment* ToComment() {
1036 return this;
1037 }
1038 virtual const XMLComment* ToComment() const {
1039 return this;
1040 }
Lee Thomasonce0763e2012-01-11 15:43:54 -08001041
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001043
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1045 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -08001046
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001047protected:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02001048 explicit XMLComment( XMLDocument* doc );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 virtual ~XMLComment();
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001050
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001051 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001052
Lee Thomason3f57d272012-01-11 15:30:03 -08001053private:
Dmitry-Mef547a992015-01-09 15:17:09 +03001054 XMLComment( const XMLComment& ); // not supported
1055 XMLComment& operator=( const XMLComment& ); // not supported
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001056};
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001057
1058
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001059/** In correct XML the declaration is the first entry in the file.
1060 @verbatim
1061 <?xml version="1.0" standalone="yes"?>
1062 @endverbatim
1063
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001064 TinyXML-2 will happily read or write files without a declaration,
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001065 however.
1066
1067 The text of the declaration isn't interpreted. It is parsed
1068 and written as a string.
1069*/
PKEuS16ed47d2013-07-06 12:02:43 +02001070class TINYXML2_LIB XMLDeclaration : public XMLNode
Lee Thomason50f97b22012-02-11 16:33:40 -08001071{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 friend class XMLDocument;
Lee Thomason50f97b22012-02-11 16:33:40 -08001073public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 virtual XMLDeclaration* ToDeclaration() {
1075 return this;
1076 }
1077 virtual const XMLDeclaration* ToDeclaration() const {
1078 return this;
1079 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001080
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -08001082
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1084 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -08001085
1086protected:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02001087 explicit XMLDeclaration( XMLDocument* doc );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 virtual ~XMLDeclaration();
Dmitry-Mef547a992015-01-09 15:17:09 +03001089
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001090 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001091
Dmitry-Mef547a992015-01-09 15:17:09 +03001092private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 XMLDeclaration( const XMLDeclaration& ); // not supported
1094 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -08001095};
1096
1097
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001098/** Any tag that TinyXML-2 doesn't recognize is saved as an
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001099 unknown. It is a tag of text, but should not be modified.
1100 It will be written back to the XML, unchanged, when the file
1101 is saved.
1102
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001103 DTD tags get thrown into XMLUnknowns.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001104*/
PKEuS16ed47d2013-07-06 12:02:43 +02001105class TINYXML2_LIB XMLUnknown : public XMLNode
Lee Thomason50f97b22012-02-11 16:33:40 -08001106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 friend class XMLDocument;
Lee Thomason50f97b22012-02-11 16:33:40 -08001108public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 virtual XMLUnknown* ToUnknown() {
1110 return this;
1111 }
1112 virtual const XMLUnknown* ToUnknown() const {
1113 return this;
1114 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001115
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -08001117
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1119 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -08001120
1121protected:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02001122 explicit XMLUnknown( XMLDocument* doc );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 virtual ~XMLUnknown();
Dmitry-Mef547a992015-01-09 15:17:09 +03001124
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001125 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001126
Dmitry-Mef547a992015-01-09 15:17:09 +03001127private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 XMLUnknown( const XMLUnknown& ); // not supported
1129 XMLUnknown& operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -08001130};
1131
1132
Lee Thomason1ff38e02012-02-14 18:18:16 -08001133
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001134/** An attribute is a name-value pair. Elements have an arbitrary
1135 number of attributes, each with a unique name.
1136
1137 @note The attributes are not XMLNodes. You may only query the
1138 Next() attribute in a list.
1139*/
PKEuS16ed47d2013-07-06 12:02:43 +02001140class TINYXML2_LIB XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 friend class XMLElement;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001143public:
Lee Thomason2fa81722012-11-09 12:37:46 -08001144 /// The name of the attribute.
Michael Daumling21626882013-10-22 17:03:37 +02001145 const char* Name() const;
1146
Lee Thomason2fa81722012-11-09 12:37:46 -08001147 /// The value of the attribute.
Michael Daumling21626882013-10-22 17:03:37 +02001148 const char* Value() const;
1149
kezenatorec694152016-11-26 17:21:43 +10001150 /// Gets the line number the attribute is in, if the document was parsed from a file.
kezenator19d8ea82016-11-29 19:50:27 +10001151 int GetLineNum() const { return _parseLineNum; }
kezenatorec694152016-11-26 17:21:43 +10001152
Lee Thomason2fa81722012-11-09 12:37:46 -08001153 /// The next attribute in the list.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 const XMLAttribute* Next() const {
MortenMacFly4ee49f12013-01-14 20:03:14 +01001155 return _next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001157
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001158 /** IntValue interprets the attribute as an integer, and returns the value.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 If the value isn't an integer, 0 will be returned. There is no error checking;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001160 use QueryIntValue() if you need error checking.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 */
Lee Thomason51c12712016-06-04 20:18:49 -07001162 int IntValue() const {
1163 int i = 0;
1164 QueryIntValue(&i);
1165 return i;
1166 }
1167
1168 int64_t Int64Value() const {
1169 int64_t i = 0;
1170 QueryInt64Value(&i);
1171 return i;
1172 }
1173
cugone75a5acc2019-04-11 22:03:43 -05001174 uint64_t Unsigned64Value() const {
1175 uint64_t i = 0;
1176 QueryUnsigned64Value(&i);
1177 return i;
1178 }
1179
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001180 /// Query as an unsigned integer. See IntValue()
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 unsigned UnsignedValue() const {
1182 unsigned i=0;
1183 QueryUnsignedValue( &i );
1184 return i;
1185 }
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001186 /// Query as a boolean. See IntValue()
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 bool BoolValue() const {
1188 bool b=false;
1189 QueryBoolValue( &b );
1190 return b;
1191 }
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001192 /// Query as a double. See IntValue()
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 double DoubleValue() const {
1194 double d=0;
1195 QueryDoubleValue( &d );
1196 return d;
1197 }
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001198 /// Query as a float. See IntValue()
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 float FloatValue() const {
1200 float f=0;
1201 QueryFloatValue( &f );
1202 return f;
1203 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001204
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001205 /** QueryIntValue interprets the attribute as an integer, and returns the value
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001206 in the provided parameter. The function will return XML_SUCCESS on success,
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1208 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001209 XMLError QueryIntValue( int* value ) const;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001210 /// See QueryIntValue
Lee Thomason2fa81722012-11-09 12:37:46 -08001211 XMLError QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason51c12712016-06-04 20:18:49 -07001212 /// See QueryIntValue
1213 XMLError QueryInt64Value(int64_t* value) const;
cugone75a5acc2019-04-11 22:03:43 -05001214 /// See QueryIntValue
1215 XMLError QueryUnsigned64Value(uint64_t* value) const;
Lee Thomason51c12712016-06-04 20:18:49 -07001216 /// See QueryIntValue
Lee Thomason2fa81722012-11-09 12:37:46 -08001217 XMLError QueryBoolValue( bool* value ) const;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001218 /// See QueryIntValue
Lee Thomason2fa81722012-11-09 12:37:46 -08001219 XMLError QueryDoubleValue( double* value ) const;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001220 /// See QueryIntValue
Lee Thomason2fa81722012-11-09 12:37:46 -08001221 XMLError QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -08001222
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 /// Set the attribute to a string value.
1224 void SetAttribute( const char* value );
1225 /// Set the attribute to value.
1226 void SetAttribute( int value );
1227 /// Set the attribute to value.
1228 void SetAttribute( unsigned value );
Lee Thomason51c12712016-06-04 20:18:49 -07001229 /// Set the attribute to value.
1230 void SetAttribute(int64_t value);
Lee Thomasoneffdf952019-08-10 17:49:42 -07001231 /// Set the attribute to value.
1232 void SetAttribute(uint64_t value);
1233 /// Set the attribute to value.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 void SetAttribute( bool value );
1235 /// Set the attribute to value.
1236 void SetAttribute( double value );
1237 /// Set the attribute to value.
1238 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -08001239
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001240private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001242
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02001243 XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 virtual ~XMLAttribute() {}
Lee Thomason624d43f2012-10-12 10:58:48 -07001245
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 XMLAttribute( const XMLAttribute& ); // not supported
1247 void operator=( const XMLAttribute& ); // not supported
1248 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -08001249
kezenator4f756162016-11-29 19:46:27 +10001250 char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001251
Lee Thomason624d43f2012-10-12 10:58:48 -07001252 mutable StrPair _name;
1253 mutable StrPair _value;
kezenatorec694152016-11-26 17:21:43 +10001254 int _parseLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 XMLAttribute* _next;
1256 MemPool* _memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001257};
1258
1259
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001260/** The element is a container class. It has a value, the element name,
1261 and can contain other elements, text, comments, and unknowns.
1262 Elements also contain an arbitrary number of attributes.
1263*/
PKEuS16ed47d2013-07-06 12:02:43 +02001264class TINYXML2_LIB XMLElement : public XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001265{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001267public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 /// Get the name of an element (which is the Value() of the node.)
1269 const char* Name() const {
1270 return Value();
1271 }
1272 /// Set the name of the element.
1273 void SetName( const char* str, bool staticMem=false ) {
1274 SetValue( str, staticMem );
1275 }
Lee Thomason2c85a712012-01-31 08:24:24 -08001276
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 virtual XMLElement* ToElement() {
1278 return this;
1279 }
1280 virtual const XMLElement* ToElement() const {
1281 return this;
1282 }
1283 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001284
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 /** Given an attribute name, Attribute() returns the value
1286 for the attribute of that name, or null if none
1287 exists. For example:
Lee Thomason92258152012-03-24 13:05:39 -07001288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 @verbatim
1290 const char* value = ele->Attribute( "foo" );
1291 @endverbatim
Lee Thomason92258152012-03-24 13:05:39 -07001292
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 The 'value' parameter is normally null. However, if specified,
1294 the attribute will only be returned if the 'name' and 'value'
1295 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001296
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 @verbatim
1298 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1299 @endverbatim
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001300
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 rather than:
1302 @verbatim
1303 if ( ele->Attribute( "foo" ) ) {
1304 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1305 }
1306 @endverbatim
1307 */
1308 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -08001309
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 /** Given an attribute name, IntAttribute() returns the value
Lee Thomason13cbc9a2016-10-27 14:55:07 -07001311 of the attribute interpreted as an integer. The default
1312 value will be returned if the attribute isn't present,
1313 or if there is an error. (For a method with error
1314 checking, see QueryIntAttribute()).
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 */
Josh Wittnercf3dd092016-10-11 18:57:17 -07001316 int IntAttribute(const char* name, int defaultValue = 0) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 /// See IntAttribute()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001318 unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
Lee Thomason51c12712016-06-04 20:18:49 -07001319 /// See IntAttribute()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001320 int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
cugone75a5acc2019-04-11 22:03:43 -05001321 /// See IntAttribute()
1322 uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const;
Lee Thomason51c12712016-06-04 20:18:49 -07001323 /// See IntAttribute()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001324 bool BoolAttribute(const char* name, bool defaultValue = false) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001325 /// See IntAttribute()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001326 double DoubleAttribute(const char* name, double defaultValue = 0) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 /// See IntAttribute()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001328 float FloatAttribute(const char* name, float defaultValue = 0) const;
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001329
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 /** Given an attribute name, QueryIntAttribute() returns
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001331 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1333 doesn't exist. If successful, the result of the conversion
1334 will be written to 'value'. If not successful, nothing will
1335 be written to 'value'. This allows you to provide default
1336 value:
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001337
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 @verbatim
1339 int value = 10;
1340 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1341 @endverbatim
1342 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001343 XMLError QueryIntAttribute( const char* name, int* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 const XMLAttribute* a = FindAttribute( name );
1345 if ( !a ) {
1346 return XML_NO_ATTRIBUTE;
1347 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001348 return a->QueryIntValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 }
Lee Thomason51c12712016-06-04 20:18:49 -07001350
1351 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001352 XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 const XMLAttribute* a = FindAttribute( name );
1354 if ( !a ) {
1355 return XML_NO_ATTRIBUTE;
1356 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001357 return a->QueryUnsignedValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 }
Lee Thomason51c12712016-06-04 20:18:49 -07001359
1360 /// See QueryIntAttribute()
1361 XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
1362 const XMLAttribute* a = FindAttribute(name);
1363 if (!a) {
1364 return XML_NO_ATTRIBUTE;
1365 }
1366 return a->QueryInt64Value(value);
1367 }
1368
cugone75a5acc2019-04-11 22:03:43 -05001369 /// See QueryIntAttribute()
1370 XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const {
1371 const XMLAttribute* a = FindAttribute(name);
1372 if(!a) {
1373 return XML_NO_ATTRIBUTE;
1374 }
1375 return a->QueryUnsigned64Value(value);
1376 }
1377
Lee Thomason51c12712016-06-04 20:18:49 -07001378 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001379 XMLError QueryBoolAttribute( const char* name, bool* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 const XMLAttribute* a = FindAttribute( name );
1381 if ( !a ) {
1382 return XML_NO_ATTRIBUTE;
1383 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001384 return a->QueryBoolValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 }
1386 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001387 XMLError QueryDoubleAttribute( const char* name, double* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 const XMLAttribute* a = FindAttribute( name );
1389 if ( !a ) {
1390 return XML_NO_ATTRIBUTE;
1391 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 return a->QueryDoubleValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 /// See QueryIntAttribute()
Lee Thomason2fa81722012-11-09 12:37:46 -08001395 XMLError QueryFloatAttribute( const char* name, float* value ) const {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 const XMLAttribute* a = FindAttribute( name );
1397 if ( !a ) {
1398 return XML_NO_ATTRIBUTE;
1399 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 return a->QueryFloatValue( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001402
Lee Thomason5b00e062017-12-28 14:07:47 -08001403 /// See QueryIntAttribute()
1404 XMLError QueryStringAttribute(const char* name, const char** value) const {
1405 const XMLAttribute* a = FindAttribute(name);
1406 if (!a) {
1407 return XML_NO_ATTRIBUTE;
1408 }
1409 *value = a->Value();
1410 return XML_SUCCESS;
1411 }
1412
1413
Lee Thomason70d942e2018-06-29 15:31:59 -07001414
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001415 /** Given an attribute name, QueryAttribute() returns
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001416 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001417 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1418 doesn't exist. It is overloaded for the primitive types,
1419 and is a generally more convenient replacement of
1420 QueryIntAttribute() and related functions.
Lee Thomason70d942e2018-06-29 15:31:59 -07001421
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001422 If successful, the result of the conversion
1423 will be written to 'value'. If not successful, nothing will
1424 be written to 'value'. This allows you to provide default
1425 value:
1426
1427 @verbatim
1428 int value = 10;
1429 QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1430 @endverbatim
1431 */
Lee Thomasonfc80df32018-06-29 15:37:29 -07001432 XMLError QueryAttribute( const char* name, int* value ) const {
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001433 return QueryIntAttribute( name, value );
1434 }
1435
Lee Thomasonfc80df32018-06-29 15:37:29 -07001436 XMLError QueryAttribute( const char* name, unsigned int* value ) const {
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001437 return QueryUnsignedAttribute( name, value );
1438 }
1439
Lee Thomasonfc80df32018-06-29 15:37:29 -07001440 XMLError QueryAttribute(const char* name, int64_t* value) const {
Lee Thomason51c12712016-06-04 20:18:49 -07001441 return QueryInt64Attribute(name, value);
1442 }
1443
Lee Thomasoneffdf952019-08-10 17:49:42 -07001444 XMLError QueryAttribute(const char* name, uint64_t* value) const {
1445 return QueryUnsigned64Attribute(name, value);
1446 }
1447
1448 XMLError QueryAttribute( const char* name, bool* value ) const {
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001449 return QueryBoolAttribute( name, value );
1450 }
1451
Lee Thomasonfc80df32018-06-29 15:37:29 -07001452 XMLError QueryAttribute( const char* name, double* value ) const {
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001453 return QueryDoubleAttribute( name, value );
1454 }
1455
Lee Thomasonfc80df32018-06-29 15:37:29 -07001456 XMLError QueryAttribute( const char* name, float* value ) const {
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001457 return QueryFloatAttribute( name, value );
1458 }
1459
justnope5ee20fe2020-06-15 00:47:48 +02001460 XMLError QueryAttribute(const char* name, const char** value) const {
1461 return QueryStringAttribute(name, value);
Lee Thomason46379652020-07-02 15:23:00 -07001462 }
justnope5ee20fe2020-06-15 00:47:48 +02001463
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -08001464 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 void SetAttribute( const char* name, const char* value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001467 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 }
1469 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 void SetAttribute( const char* name, int value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 }
1474 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 void SetAttribute( const char* name, unsigned value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 }
Lee Thomason51c12712016-06-04 20:18:49 -07001479
1480 /// Sets the named attribute to value.
1481 void SetAttribute(const char* name, int64_t value) {
1482 XMLAttribute* a = FindOrCreateAttribute(name);
1483 a->SetAttribute(value);
1484 }
1485
Lee Thomasoneffdf952019-08-10 17:49:42 -07001486 /// Sets the named attribute to value.
1487 void SetAttribute(const char* name, uint64_t value) {
1488 XMLAttribute* a = FindOrCreateAttribute(name);
1489 a->SetAttribute(value);
1490 }
netcandfb45cb2020-02-15 21:35:58 +08001491
Lee Thomasoneffdf952019-08-10 17:49:42 -07001492 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 void SetAttribute( const char* name, bool value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 /// Sets the named attribute to value.
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 void SetAttribute( const char* name, double value ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 XMLAttribute* a = FindOrCreateAttribute( name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 a->SetAttribute( value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001502 /// Sets the named attribute to value.
1503 void SetAttribute( const char* name, float value ) {
1504 XMLAttribute* a = FindOrCreateAttribute( name );
1505 a->SetAttribute( value );
1506 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001507
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 /**
1509 Delete an attribute.
1510 */
1511 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -08001512
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 /// Return the first attribute in the list.
1514 const XMLAttribute* FirstAttribute() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 return _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 }
1517 /// Query a specific attribute in the list.
1518 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -08001519
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 /** Convenience function for easy access to the text inside an element. Although easy
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001521 and concise, GetText() is limited compared to getting the XMLText child
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 and accessing it directly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001523
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001524 If the first child of 'this' is a XMLText, the GetText()
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 returns the character string of the Text node, else null is returned.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001526
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 This is a convenient method for getting the text of simple contained text:
1528 @verbatim
1529 <foo>This is text</foo>
1530 const char* str = fooElement->GetText();
1531 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001532
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 'str' will be a pointer to "This is text".
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001534
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 Note that this function can be misleading. If the element foo was created from
1536 this XML:
1537 @verbatim
1538 <foo><b>This is text</b></foo>
1539 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001540
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 then the value of str would be null. The first child node isn't a text node, it is
1542 another element. From this XML:
1543 @verbatim
1544 <foo>This is <b>text</b></foo>
1545 @endverbatim
1546 GetText() will return "This is ".
1547 */
1548 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -08001549
Uli Kusterer85fff5e2014-01-21 01:35:30 +01001550 /** Convenience function for easy access to the text inside an element. Although easy
1551 and concise, SetText() is limited compared to creating an XMLText child
1552 and mutating it directly.
1553
1554 If the first child of 'this' is a XMLText, SetText() sets its value to
1555 the given string, otherwise it will create a first child that is an XMLText.
1556
1557 This is a convenient method for setting the text of simple contained text:
1558 @verbatim
1559 <foo>This is text</foo>
1560 fooElement->SetText( "Hullaballoo!" );
1561 <foo>Hullaballoo!</foo>
1562 @endverbatim
1563
1564 Note that this function can be misleading. If the element foo was created from
1565 this XML:
1566 @verbatim
1567 <foo><b>This is text</b></foo>
1568 @endverbatim
1569
1570 then it will not change "This is text", but rather prefix it with a text element:
1571 @verbatim
1572 <foo>Hullaballoo!<b>This is text</b></foo>
1573 @endverbatim
Lee Thomason70d942e2018-06-29 15:31:59 -07001574
Uli Kusterer85fff5e2014-01-21 01:35:30 +01001575 For this XML:
1576 @verbatim
1577 <foo />
1578 @endverbatim
1579 SetText() will generate
1580 @verbatim
1581 <foo>Hullaballoo!</foo>
1582 @endverbatim
1583 */
Lee Thomason5bb2d802014-01-24 10:42:57 -08001584 void SetText( const char* inText );
Dmitry-Me9e9c85b2015-10-19 18:04:46 +03001585 /// Convenience method for setting text inside an element. See SetText() for important limitations.
Lee Thomason5bb2d802014-01-24 10:42:57 -08001586 void SetText( int value );
Dmitry-Me9e9c85b2015-10-19 18:04:46 +03001587 /// Convenience method for setting text inside an element. See SetText() for important limitations.
Lee Thomason70d942e2018-06-29 15:31:59 -07001588 void SetText( unsigned value );
Lee Thomason51c12712016-06-04 20:18:49 -07001589 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1590 void SetText(int64_t value);
cugone47e229e2019-04-12 17:27:28 -05001591 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1592 void SetText(uint64_t value);
Lee Thomason51c12712016-06-04 20:18:49 -07001593 /// Convenience method for setting text inside an element. See SetText() for important limitations.
Lee Thomason70d942e2018-06-29 15:31:59 -07001594 void SetText( bool value );
Dmitry-Me9e9c85b2015-10-19 18:04:46 +03001595 /// Convenience method for setting text inside an element. See SetText() for important limitations.
Lee Thomason70d942e2018-06-29 15:31:59 -07001596 void SetText( double value );
Dmitry-Me9e9c85b2015-10-19 18:04:46 +03001597 /// Convenience method for setting text inside an element. See SetText() for important limitations.
Lee Thomason70d942e2018-06-29 15:31:59 -07001598 void SetText( float value );
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001599
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 /**
1601 Convenience method to query the value of a child text node. This is probably best
1602 shown by example. Given you have a document is this form:
1603 @verbatim
1604 <point>
1605 <x>1</x>
1606 <y>1.4</y>
1607 </point>
1608 @endverbatim
Lee Thomason21be8822012-07-15 17:27:22 -07001609
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 The QueryIntText() and similar functions provide a safe and easier way to get to the
1611 "value" of x and y.
Lee Thomason21be8822012-07-15 17:27:22 -07001612
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 @verbatim
1614 int x = 0;
1615 float y = 0; // types of x and y are contrived for example
1616 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1617 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1618 xElement->QueryIntText( &x );
1619 yElement->QueryFloatText( &y );
1620 @endverbatim
Lee Thomason21be8822012-07-15 17:27:22 -07001621
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1623 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001624
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 */
MortenMacFly4ee49f12013-01-14 20:03:14 +01001626 XMLError QueryIntText( int* ival ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001628 XMLError QueryUnsignedText( unsigned* uval ) const;
Lee Thomason51c12712016-06-04 20:18:49 -07001629 /// See QueryIntText()
1630 XMLError QueryInt64Text(int64_t* uval) const;
1631 /// See QueryIntText()
cugone47e229e2019-04-12 17:27:28 -05001632 XMLError QueryUnsigned64Text(uint64_t* uval) const;
1633 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001634 XMLError QueryBoolText( bool* bval ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001636 XMLError QueryDoubleText( double* dval ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 /// See QueryIntText()
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638 XMLError QueryFloatText( float* fval ) const;
Lee Thomason21be8822012-07-15 17:27:22 -07001639
Josh Wittnercf3dd092016-10-11 18:57:17 -07001640 int IntText(int defaultValue = 0) const;
1641
Josh Wittner3a621f52016-09-12 19:17:54 -07001642 /// See QueryIntText()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001643 unsigned UnsignedText(unsigned defaultValue = 0) const;
Josh Wittner3a621f52016-09-12 19:17:54 -07001644 /// See QueryIntText()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001645 int64_t Int64Text(int64_t defaultValue = 0) const;
cugone47e229e2019-04-12 17:27:28 -05001646 /// See QueryIntText()
1647 uint64_t Unsigned64Text(uint64_t defaultValue = 0) const;
Josh Wittner3a621f52016-09-12 19:17:54 -07001648 /// See QueryIntText()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001649 bool BoolText(bool defaultValue = false) const;
Josh Wittner3a621f52016-09-12 19:17:54 -07001650 /// See QueryIntText()
Josh Wittnercf3dd092016-10-11 18:57:17 -07001651 double DoubleText(double defaultValue = 0) const;
Josh Wittner3a621f52016-09-12 19:17:54 -07001652 /// See QueryIntText()
ngc92e6202452019-12-03 16:25:53 +01001653 float FloatText(float defaultValue = 0) const;
1654
1655 /**
1656 Convenience method to create a new XMLElement and add it as last (right)
1657 child of this node. Returns the created and inserted element.
1658 */
Lee Thomasone4442682020-03-01 17:10:38 -08001659 XMLElement* InsertNewChildElement(const char* name);
1660 /// See InsertNewChildElement()
1661 XMLComment* InsertNewComment(const char* comment);
1662 /// See InsertNewChildElement()
1663 XMLText* InsertNewText(const char* text);
1664 /// See InsertNewChildElement()
1665 XMLDeclaration* InsertNewDeclaration(const char* text);
1666 /// See InsertNewChildElement()
1667 XMLUnknown* InsertNewUnknown(const char* text);
ngc92e6202452019-12-03 16:25:53 +01001668
Josh Wittner3a621f52016-09-12 19:17:54 -07001669
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 // internal:
Dmitry-Mee5035632017-04-05 18:02:40 +03001671 enum ElementClosingType {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 OPEN, // <foo>
1673 CLOSED, // <foo/>
1674 CLOSING // </foo>
1675 };
Dmitry-Mee5035632017-04-05 18:02:40 +03001676 ElementClosingType ClosingType() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 return _closingType;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1680 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001681
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001682protected:
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001683 char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
Dmitry-Me9b0f1772015-04-03 10:37:31 +03001684
Lee Thomason50adb4c2012-02-13 15:07:09 -08001685private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 XMLElement( XMLDocument* doc );
1687 virtual ~XMLElement();
1688 XMLElement( const XMLElement& ); // not supported
1689 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001690
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 XMLAttribute* FindOrCreateAttribute( const char* name );
kezenator4f756162016-11-29 19:46:27 +10001692 char* ParseAttributes( char* p, int* curLineNumPtr );
Dmitry-Mee3225b12014-09-03 11:03:11 +04001693 static void DeleteAttribute( XMLAttribute* attribute );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001694 XMLAttribute* CreateAttribute();
Lee Thomason67d61312012-01-24 16:01:51 -08001695
Lee Thomason5bb2d802014-01-24 10:42:57 -08001696 enum { BUF_SIZE = 200 };
Dmitry-Mee5035632017-04-05 18:02:40 +03001697 ElementClosingType _closingType;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 // The attribute list is ordered; there is no 'lastAttribute'
1699 // because the list needs to be scanned for dupes before adding
1700 // a new attribute.
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 XMLAttribute* _rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001702};
1703
1704
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001705enum Whitespace {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 PRESERVE_WHITESPACE,
1707 COLLAPSE_WHITESPACE
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001708};
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001709
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001710
1711/** A Document binds together all the functionality.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001712 It can be saved, loaded, and printed to the screen.
1713 All Nodes are connected and allocated to a Document.
1714 If the Document is deleted, all its Nodes are also deleted.
1715*/
PKEuS16ed47d2013-07-06 12:02:43 +02001716class TINYXML2_LIB XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001717{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 friend class XMLElement;
Lee Thomasond946dda2018-04-05 09:11:08 -07001719 // Gives access to SetError and Push/PopDepth, but over-access for everything else.
Lee Thomasonf49b9652017-10-11 10:57:49 -07001720 // Wishing C++ had "internal" scope.
Lee Thomason70d942e2018-06-29 15:31:59 -07001721 friend class XMLNode;
Lee Thomasonf49b9652017-10-11 10:57:49 -07001722 friend class XMLText;
1723 friend class XMLComment;
1724 friend class XMLDeclaration;
1725 friend class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001726public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 /// constructor
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001728 XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001730
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 virtual XMLDocument* ToDocument() {
Dmitry-Me66487eb2015-07-20 18:21:04 +03001732 TIXMLASSERT( this == _document );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 return this;
1734 }
1735 virtual const XMLDocument* ToDocument() const {
Dmitry-Me66487eb2015-07-20 18:21:04 +03001736 TIXMLASSERT( this == _document );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 return this;
1738 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001739
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 /**
1741 Parse an XML file from a character string.
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001742 Returns XML_SUCCESS (0) on success, or
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 an errorID.
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001744
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 You may optionally pass in the 'nBytes', which is
1746 the number of bytes which will be parsed. If not
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001747 specified, TinyXML-2 will assume 'xml' points to a
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 null terminated string.
1749 */
orbitcowboy710a3322019-05-16 15:30:47 +02001750 XMLError Parse( const char* xml, size_t nBytes=static_cast<size_t>(-1) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001751
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 /**
1753 Load an XML file from disk.
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001754 Returns XML_SUCCESS (0) on success, or
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 an errorID.
1756 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001757 XMLError LoadFile( const char* filename );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001758
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 /**
1760 Load an XML file from disk. You are responsible
Lee Thomason70d942e2018-06-29 15:31:59 -07001761 for providing and closing the FILE*.
1762
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001763 NOTE: The file should be opened as binary ("rb")
1764 not text in order for TinyXML-2 to correctly
1765 do newline normalization.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001766
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001767 Returns XML_SUCCESS (0) on success, or
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 an errorID.
1769 */
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001770 XMLError LoadFile( FILE* );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 /**
1773 Save the XML file to disk.
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001774 Returns XML_SUCCESS (0) on success, or
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 an errorID.
1776 */
Lee Thomason2fa81722012-11-09 12:37:46 -08001777 XMLError SaveFile( const char* filename, bool compact = false );
Lee Thomasond11cd162012-04-12 08:35:36 -07001778
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 /**
1780 Save the XML file to disk. You are responsible
1781 for providing and closing the FILE*.
Ken Miller81da1fb2012-04-09 23:32:26 -05001782
Benjamin Doherty3b9cf992016-09-23 18:42:23 -06001783 Returns XML_SUCCESS (0) on success, or
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 an errorID.
1785 */
Jerome Martinez242c3ea2013-01-06 12:20:04 +01001786 XMLError SaveFile( FILE* fp, bool compact = false );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001787
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 bool ProcessEntities() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _processEntities;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 }
1791 Whitespace WhitespaceMode() const {
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001792 return _whitespaceMode;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001794
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 /**
1796 Returns true if this document has a leading Byte Order Mark of UTF8.
1797 */
1798 bool HasBOM() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 return _writeBOM;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 }
1801 /** Sets whether to write the BOM when writing the file.
1802 */
1803 void SetBOM( bool useBOM ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 _writeBOM = useBOM;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001806
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 /** Return the root element of DOM. Equivalent to FirstChildElement().
1808 To get the first node, use FirstChild().
1809 */
1810 XMLElement* RootElement() {
1811 return FirstChildElement();
1812 }
1813 const XMLElement* RootElement() const {
1814 return FirstChildElement();
1815 }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001816
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 /** Print the Document. If the Printer is not provided, it will
1818 print to stdout. If you provide Printer, this can print to a file:
1819 @verbatim
1820 XMLPrinter printer( fp );
1821 doc.Print( &printer );
1822 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001823
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 Or you can use a printer to print to memory:
1825 @verbatim
1826 XMLPrinter printer;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001827 doc.Print( &printer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 // printer.CStr() has a const char* to the XML
1829 @endverbatim
1830 */
PKEuS1c5f99e2013-07-06 11:28:39 +02001831 void Print( XMLPrinter* streamer=0 ) const;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001833
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 /**
1835 Create a new Element associated with
1836 this Document. The memory for the Element
1837 is managed by the Document.
1838 */
1839 XMLElement* NewElement( const char* name );
1840 /**
1841 Create a new Comment associated with
1842 this Document. The memory for the Comment
1843 is managed by the Document.
1844 */
1845 XMLComment* NewComment( const char* comment );
1846 /**
1847 Create a new Text associated with
1848 this Document. The memory for the Text
1849 is managed by the Document.
1850 */
1851 XMLText* NewText( const char* text );
1852 /**
1853 Create a new Declaration associated with
1854 this Document. The memory for the object
1855 is managed by the Document.
Lee Thomasonf68c4382012-04-28 14:37:11 -07001856
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 If the 'text' param is null, the standard
1858 declaration is used.:
1859 @verbatim
1860 <?xml version="1.0" encoding="UTF-8"?>
1861 @endverbatim
1862 */
1863 XMLDeclaration* NewDeclaration( const char* text=0 );
1864 /**
1865 Create a new Unknown associated with
Andrew C. Martin0fd87462013-03-09 20:09:45 -07001866 this Document. The memory for the object
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 is managed by the Document.
1868 */
1869 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001870
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 /**
1872 Delete a node associated with this document.
1873 It will be unlinked from the DOM.
1874 */
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001875 void DeleteNode( XMLNode* node );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001876
ngc922c6a41a2020-07-30 23:51:30 +03001877 /// Clears the error flags.
1878 void ClearError();
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001879
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 /// Return true if there was an error parsing the document.
1881 bool Error() const {
Lee Thomason85536252016-06-04 19:10:53 -07001882 return _errorID != XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 /// Return the errorID.
Lee Thomason2fa81722012-11-09 12:37:46 -08001885 XMLError ErrorID() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 }
Lee Thomason331596e2014-09-11 14:56:43 -07001888 const char* ErrorName() const;
Lee Thomasone90e9012016-12-24 07:34:39 -08001889 static const char* ErrorIDToName(XMLError errorID);
Lee Thomason331596e2014-09-11 14:56:43 -07001890
Lee Thomason70d942e2018-06-29 15:31:59 -07001891 /** Returns a "long form" error description. A hopefully helpful
Lee Thomasonf49b9652017-10-11 10:57:49 -07001892 diagnostic with location, line number, and/or additional info.
1893 */
1894 const char* ErrorStr() const;
1895
1896 /// A (trivial) utility function that prints the ErrorStr() to stdout.
1897 void PrintError() const;
Lee Thomason8c9e3132017-06-26 16:55:01 -07001898
orbitcowboy22b21ec2018-07-17 11:52:57 +02001899 /// Return the line where the error occurred, or zero if unknown.
Lee Thomasonf49b9652017-10-11 10:57:49 -07001900 int ErrorLineNum() const
kezenatorec694152016-11-26 17:21:43 +10001901 {
1902 return _errorLineNum;
1903 }
Lee Thomason70d942e2018-06-29 15:31:59 -07001904
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001905 /// Clear the document, resetting it to the initial state.
1906 void Clear();
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001907
Lee Thomason7085f002017-06-01 18:09:43 -07001908 /**
Lee Thomasonb29f5562017-06-01 18:45:32 -07001909 Copies this document to a target document.
Lee Thomason7085f002017-06-01 18:09:43 -07001910 The target will be completely cleared before the copy.
Lee Thomasonb29f5562017-06-01 18:45:32 -07001911 If you want to copy a sub-tree, see XMLNode::DeepClone().
Lee Thomason7085f002017-06-01 18:09:43 -07001912
Lee Thomason1346a172017-06-14 15:14:19 -07001913 NOTE: that the 'target' must be non-null.
Lee Thomason7085f002017-06-01 18:09:43 -07001914 */
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09001915 void DeepCopy(XMLDocument* target) const;
Lee Thomason7085f002017-06-01 18:09:43 -07001916
1917 // internal
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001919
Lee Thomason816d3fa2017-06-05 14:35:55 -07001920 // internal
orbitcowboy73f54092019-08-14 09:30:30 +02001921 void MarkInUse(const XMLNode* const);
Lee Thomason816d3fa2017-06-05 14:35:55 -07001922
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
1924 return 0;
1925 }
1926 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const {
1927 return false;
1928 }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001929
Lee Thomason3f57d272012-01-11 15:30:03 -08001930private:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 XMLDocument( const XMLDocument& ); // not supported
1932 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001933
Lee Thomasone90e9012016-12-24 07:34:39 -08001934 bool _writeBOM;
1935 bool _processEntities;
1936 XMLError _errorID;
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001937 Whitespace _whitespaceMode;
Lee Thomasonaa188392017-09-19 17:54:31 -07001938 mutable StrPair _errorStr;
Lee Thomasone90e9012016-12-24 07:34:39 -08001939 int _errorLineNum;
1940 char* _charBuffer;
1941 int _parseCurLineNum;
Lee Thomasond946dda2018-04-05 09:11:08 -07001942 int _parsingDepth;
Lee Thomason816d3fa2017-06-05 14:35:55 -07001943 // Memory tracking does add some overhead.
1944 // However, the code assumes that you don't
1945 // have a bunch of unlinked nodes around.
1946 // Therefore it takes less memory to track
1947 // in the document vs. a linked list in the XMLNode,
1948 // and the performance is the same.
1949 DynArray<XMLNode*, 10> _unlinked;
Lee Thomasond1983222012-02-06 08:41:24 -08001950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 MemPoolT< sizeof(XMLElement) > _elementPool;
1952 MemPoolT< sizeof(XMLAttribute) > _attributePool;
1953 MemPoolT< sizeof(XMLText) > _textPool;
1954 MemPoolT< sizeof(XMLComment) > _commentPool;
Lee Thomason331596e2014-09-11 14:56:43 -07001955
1956 static const char* _errorNames[XML_ERROR_COUNT];
Dmitry-Me97476b72015-01-01 16:15:57 +03001957
1958 void Parse();
Dmitry-Me2aebfb72017-02-27 15:53:40 +03001959
Lee Thomasonf49b9652017-10-11 10:57:49 -07001960 void SetError( XMLError error, int lineNum, const char* format, ... );
1961
Lee Thomasond946dda2018-04-05 09:11:08 -07001962 // Something of an obvious security hole, once it was discovered.
1963 // Either an ill-formed XML or an excessively deep one can overflow
1964 // the stack. Track stack depth, and error out if needed.
1965 class DepthTracker {
1966 public:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02001967 explicit DepthTracker(XMLDocument * document) {
Lee Thomason70d942e2018-06-29 15:31:59 -07001968 this->_document = document;
Lee Thomasond946dda2018-04-05 09:11:08 -07001969 document->PushDepth();
1970 }
1971 ~DepthTracker() {
1972 _document->PopDepth();
1973 }
1974 private:
1975 XMLDocument * _document;
1976 };
Lee Thomasonf928c352018-04-05 09:24:20 -07001977 void PushDepth();
1978 void PopDepth();
Lee Thomasond946dda2018-04-05 09:11:08 -07001979
Dmitry-Me2aebfb72017-02-27 15:53:40 +03001980 template<class NodeType, int PoolElementSize>
1981 NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
Lee Thomason5cae8972012-01-24 18:03:07 -08001982};
1983
Dmitry-Me2aebfb72017-02-27 15:53:40 +03001984template<class NodeType, int PoolElementSize>
1985inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
1986{
1987 TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
1988 TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
1989 NodeType* returnNode = new (pool.Alloc()) NodeType( this );
1990 TIXMLASSERT( returnNode );
1991 returnNode->_memPool = &pool;
Lee Thomason816d3fa2017-06-05 14:35:55 -07001992
1993 _unlinked.Push(returnNode);
Dmitry-Me2aebfb72017-02-27 15:53:40 +03001994 return returnNode;
1995}
Lee Thomason7c913cd2012-01-26 18:32:34 -08001996
Lee Thomason3ffdd392012-03-28 17:27:55 -07001997/**
1998 A XMLHandle is a class that wraps a node pointer with null checks; this is
Vasily Biryukov9a975b72013-05-11 21:41:42 +06001999 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
Lee Thomason3ffdd392012-03-28 17:27:55 -07002000 DOM structure. It is a separate utility class.
2001
2002 Take an example:
2003 @verbatim
2004 <Document>
2005 <Element attributeA = "valueA">
2006 <Child attributeB = "value1" />
2007 <Child attributeB = "value2" />
2008 </Element>
Thomas Roß08bdf502012-05-12 14:21:23 +02002009 </Document>
Lee Thomason3ffdd392012-03-28 17:27:55 -07002010 @endverbatim
2011
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002012 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
Lee Thomason3ffdd392012-03-28 17:27:55 -07002013 easy to write a *lot* of code that looks like:
2014
2015 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002016 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07002017 if ( root )
2018 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002019 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07002020 if ( element )
2021 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002022 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07002023 if ( child )
2024 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002025 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07002026 if ( child2 )
2027 {
2028 // Finally do something useful.
2029 @endverbatim
2030
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002031 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002032 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07002033 and correct to use:
2034
2035 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07002036 XMLHandle docHandle( &document );
Dmitry-Mea317bd62014-12-08 10:35:37 +03002037 XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07002038 if ( child2 )
2039 {
2040 // do something useful
2041 @endverbatim
2042
2043 Which is MUCH more concise and useful.
2044
2045 It is also safe to copy handles - internally they are nothing more than node pointers.
2046 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002047 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07002048 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002049
2050 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07002051*/
PKEuS16ed47d2013-07-06 12:02:43 +02002052class TINYXML2_LIB XMLHandle
Lee Thomason3ffdd392012-03-28 17:27:55 -07002053{
2054public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02002056 explicit XMLHandle( XMLNode* node ) : _node( node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 }
2058 /// Create a handle from a node.
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02002059 explicit XMLHandle( XMLNode& node ) : _node( &node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 }
2061 /// Copy constructor
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002062 XMLHandle( const XMLHandle& ref ) : _node( ref._node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 }
2064 /// Assignment
2065 XMLHandle& operator=( const XMLHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 return *this;
2068 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07002069
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 /// Get the first child of this handle.
2071 XMLHandle FirstChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 return XMLHandle( _node ? _node->FirstChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 }
2074 /// Get the first child element of this handle.
Dmitry-Me886ad972015-07-22 11:00:51 +03002075 XMLHandle FirstChildElement( const char* name = 0 ) {
2076 return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
2078 /// Get the last child of this handle.
2079 XMLHandle LastChild() {
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 return XMLHandle( _node ? _node->LastChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 }
2082 /// Get the last child element of this handle.
Dmitry-Me886ad972015-07-22 11:00:51 +03002083 XMLHandle LastChildElement( const char* name = 0 ) {
2084 return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 }
2086 /// Get the previous sibling of this handle.
2087 XMLHandle PreviousSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -07002088 return XMLHandle( _node ? _node->PreviousSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 }
2090 /// Get the previous sibling element of this handle.
Dmitry-Me886ad972015-07-22 11:00:51 +03002091 XMLHandle PreviousSiblingElement( const char* name = 0 ) {
2092 return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 }
2094 /// Get the next sibling of this handle.
2095 XMLHandle NextSibling() {
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 return XMLHandle( _node ? _node->NextSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 }
2098 /// Get the next sibling element of this handle.
Dmitry-Me886ad972015-07-22 11:00:51 +03002099 XMLHandle NextSiblingElement( const char* name = 0 ) {
2100 return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07002102
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 /// Safe cast to XMLNode. This can return null.
2104 XMLNode* ToNode() {
Lee Thomason624d43f2012-10-12 10:58:48 -07002105 return _node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 }
2107 /// Safe cast to XMLElement. This can return null.
2108 XMLElement* ToElement() {
Dmitry-Meebb16602016-11-16 17:22:45 +03002109 return ( _node ? _node->ToElement() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 }
2111 /// Safe cast to XMLText. This can return null.
2112 XMLText* ToText() {
Dmitry-Meebb16602016-11-16 17:22:45 +03002113 return ( _node ? _node->ToText() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 }
2115 /// Safe cast to XMLUnknown. This can return null.
2116 XMLUnknown* ToUnknown() {
Dmitry-Meebb16602016-11-16 17:22:45 +03002117 return ( _node ? _node->ToUnknown() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 }
2119 /// Safe cast to XMLDeclaration. This can return null.
2120 XMLDeclaration* ToDeclaration() {
Dmitry-Meebb16602016-11-16 17:22:45 +03002121 return ( _node ? _node->ToDeclaration() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 }
Lee Thomason3ffdd392012-03-28 17:27:55 -07002123
2124private:
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 XMLNode* _node;
Lee Thomason3ffdd392012-03-28 17:27:55 -07002126};
2127
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002128
2129/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07002130 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
2131 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07002132*/
PKEuS16ed47d2013-07-06 12:02:43 +02002133class TINYXML2_LIB XMLConstHandle
Lee Thomason8b899812012-04-04 15:58:16 -07002134{
2135public:
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02002136 explicit XMLConstHandle( const XMLNode* node ) : _node( node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
orbitcowboy2cc8a4c2018-09-05 08:46:21 +02002138 explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 }
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002140 XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 }
Lee Thomason8b899812012-04-04 15:58:16 -07002142
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 XMLConstHandle& operator=( const XMLConstHandle& ref ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 _node = ref._node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 return *this;
2146 }
Lee Thomason8b899812012-04-04 15:58:16 -07002147
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 const XMLConstHandle FirstChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 return XMLConstHandle( _node ? _node->FirstChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
Dmitry-Me886ad972015-07-22 11:00:51 +03002151 const XMLConstHandle FirstChildElement( const char* name = 0 ) const {
2152 return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
2154 const XMLConstHandle LastChild() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 return XMLConstHandle( _node ? _node->LastChild() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Dmitry-Me886ad972015-07-22 11:00:51 +03002157 const XMLConstHandle LastChildElement( const char* name = 0 ) const {
2158 return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 }
2160 const XMLConstHandle PreviousSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 }
Dmitry-Me886ad972015-07-22 11:00:51 +03002163 const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const {
2164 return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 }
2166 const XMLConstHandle NextSibling() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 return XMLConstHandle( _node ? _node->NextSibling() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 }
Dmitry-Me886ad972015-07-22 11:00:51 +03002169 const XMLConstHandle NextSiblingElement( const char* name = 0 ) const {
2170 return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 }
Lee Thomason8b899812012-04-04 15:58:16 -07002172
2173
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 const XMLNode* ToNode() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 return _node;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 }
2177 const XMLElement* ToElement() const {
Dmitry-Meebb16602016-11-16 17:22:45 +03002178 return ( _node ? _node->ToElement() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
2180 const XMLText* ToText() const {
Dmitry-Meebb16602016-11-16 17:22:45 +03002181 return ( _node ? _node->ToText() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 }
2183 const XMLUnknown* ToUnknown() const {
Dmitry-Meebb16602016-11-16 17:22:45 +03002184 return ( _node ? _node->ToUnknown() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 }
2186 const XMLDeclaration* ToDeclaration() const {
Dmitry-Meebb16602016-11-16 17:22:45 +03002187 return ( _node ? _node->ToDeclaration() : 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189
Lee Thomason5cae8972012-01-24 18:03:07 -08002190private:
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 const XMLNode* _node;
Lee Thomason56bdd022012-02-09 18:16:58 -08002192};
Lee Thomason6f381b72012-03-02 12:59:39 -08002193
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002194
2195/**
2196 Printing functionality. The XMLPrinter gives you more
2197 options than the XMLDocument::Print() method.
2198
2199 It can:
2200 -# Print to memory.
Thomas Roß08bdf502012-05-12 14:21:23 +02002201 -# Print to a file you provide.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002202 -# Print XML without a XMLDocument.
2203
2204 Print to Memory
2205
2206 @verbatim
2207 XMLPrinter printer;
Vasily Biryukov9a975b72013-05-11 21:41:42 +06002208 doc.Print( &printer );
Thomas Roß08bdf502012-05-12 14:21:23 +02002209 SomeFunction( printer.CStr() );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002210 @endverbatim
2211
2212 Print to a File
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002213
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002214 You provide the file pointer.
2215 @verbatim
2216 XMLPrinter printer( fp );
2217 doc.Print( &printer );
2218 @endverbatim
2219
2220 Print without a XMLDocument
2221
2222 When loading, an XML parser is very useful. However, sometimes
2223 when saving, it just gets in the way. The code is often set up
2224 for streaming, and constructing the DOM is just overhead.
2225
2226 The Printer supports the streaming case. The following code
2227 prints out a trivially simple XML file without ever creating
2228 an XML document.
2229
2230 @verbatim
2231 XMLPrinter printer( fp );
2232 printer.OpenElement( "foo" );
2233 printer.PushAttribute( "foo", "bar" );
2234 printer.CloseElement();
2235 @endverbatim
2236*/
PKEuS16ed47d2013-07-06 12:02:43 +02002237class TINYXML2_LIB XMLPrinter : public XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002238{
2239public:
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 /** Construct the printer. If the FILE* is specified,
2241 this will print to the FILE. Else it will print
2242 to memory, and the result is available in CStr().
2243 If 'compact' is set to true, then output is created
2244 with only required whitespace and newlines.
2245 */
PKEuS1bfb9542013-08-04 13:51:17 +02002246 XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
Dennis Jenkins59c75d32013-10-08 13:10:07 -05002247 virtual ~XMLPrinter() {}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002248
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 /** If streaming, write the BOM and declaration. */
2250 void PushHeader( bool writeBOM, bool writeDeclaration );
2251 /** If streaming, start writing an element.
2252 The element must be closed with CloseElement()
2253 */
Lee Thomason256adb62014-04-06 14:41:46 -07002254 void OpenElement( const char* name, bool compactMode=false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 /// If streaming, add an attribute to an open element.
2256 void PushAttribute( const char* name, const char* value );
2257 void PushAttribute( const char* name, int value );
2258 void PushAttribute( const char* name, unsigned value );
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002259 void PushAttribute( const char* name, int64_t value );
2260 void PushAttribute( const char* name, uint64_t value );
Lee Thomason51c12712016-06-04 20:18:49 -07002261 void PushAttribute( const char* name, bool value );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 void PushAttribute( const char* name, double value );
2263 /// If streaming, close the Element.
Lee Thomason256adb62014-04-06 14:41:46 -07002264 virtual void CloseElement( bool compactMode=false );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002265
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 /// Add a text node.
2267 void PushText( const char* text, bool cdata=false );
2268 /// Add a text node from an integer.
2269 void PushText( int value );
2270 /// Add a text node from an unsigned.
2271 void PushText( unsigned value );
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002272 /// Add a text node from a signed 64bit integer.
2273 void PushText( int64_t value );
2274 /// Add a text node from an unsigned 64bit integer.
2275 void PushText( uint64_t value );
Lee Thomason51c12712016-06-04 20:18:49 -07002276 /// Add a text node from a bool.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 void PushText( bool value );
2278 /// Add a text node from a float.
2279 void PushText( float value );
2280 /// Add a text node from a double.
2281 void PushText( double value );
Lee Thomason21be8822012-07-15 17:27:22 -07002282
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 /// Add a comment
2284 void PushComment( const char* comment );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002285
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 void PushDeclaration( const char* value );
2287 void PushUnknown( const char* value );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
2290 virtual bool VisitExit( const XMLDocument& /*doc*/ ) {
2291 return true;
2292 }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002293
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
2295 virtual bool VisitExit( const XMLElement& element );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002296
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 virtual bool Visit( const XMLText& text );
2298 virtual bool Visit( const XMLComment& comment );
2299 virtual bool Visit( const XMLDeclaration& declaration );
2300 virtual bool Visit( const XMLUnknown& unknown );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002301
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 /**
2303 If in print to memory mode, return a pointer to
2304 the XML file in memory.
2305 */
2306 const char* CStr() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002307 return _buffer.Mem();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 }
2309 /**
2310 If in print to memory mode, return the size
2311 of the XML file in memory. (Note the size returned
2312 includes the terminating null.)
2313 */
2314 int CStrSize() const {
Lee Thomason624d43f2012-10-12 10:58:48 -07002315 return _buffer.Size();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 }
Reinhard Klambauer3bc3d4e2013-11-22 14:05:21 +01002317 /**
2318 If in print to memory mode, reset the buffer to the
2319 beginning.
2320 */
Stephan Friedrichse1b30132019-03-07 21:30:23 +01002321 void ClearBuffer( bool resetToFirstElement = true ) {
Lee Thomasonce0510b2013-11-26 21:29:37 -08002322 _buffer.Clear();
Reinhard Klambauer3bc3d4e2013-11-22 14:05:21 +01002323 _buffer.Push(0);
Stephan Friedrichse1b30132019-03-07 21:30:23 +01002324 _firstElement = resetToFirstElement;
Reinhard Klambauer3bc3d4e2013-11-22 14:05:21 +01002325 }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002326
Dennis Jenkins59c75d32013-10-08 13:10:07 -05002327protected:
Alexander Maid740b642014-05-20 22:04:42 +02002328 virtual bool CompactMode( const XMLElement& ) { return _compactMode; }
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002329
Lee Thomasonc18eb232014-02-21 17:31:17 -08002330 /** Prints out the space before an element. You may override to change
2331 the space and tabs used. A PrintSpace() override should call Print().
2332 */
2333 virtual void PrintSpace( int depth );
Lee Thomason8812f192020-06-13 17:46:44 -07002334 virtual void Print( const char* format, ... );
2335 virtual void Write( const char* data, size_t size );
2336 virtual void Putc( char ch );
2337
2338 inline void Write(const char* data) { Write(data, strlen(data)); }
Lee Thomasonc18eb232014-02-21 17:31:17 -08002339
Dmitry-Mea092bc12014-12-23 17:57:05 +03002340 void SealElementIfJustOpened();
Dennis Jenkins59c75d32013-10-08 13:10:07 -05002341 bool _elementJustOpened;
2342 DynArray< const char*, 10 > _stack;
2343
2344private:
Chow Loong Jin6a514392020-03-26 16:30:37 +08002345 /**
2346 Prepares to write a new node. This includes sealing an element that was
2347 just opened, and writing any whitespace necessary if not in compact mode.
2348 */
2349 void PrepareForNewNode( bool compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002351
Lee Thomason624d43f2012-10-12 10:58:48 -07002352 bool _firstElement;
Jerome Martinez242c3ea2013-01-06 12:20:04 +01002353 FILE* _fp;
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 int _depth;
2355 int _textDepth;
2356 bool _processEntities;
Lee Thomasonc18eb232014-02-21 17:31:17 -08002357 bool _compactMode;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002358
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 enum {
2360 ENTITY_RANGE = 64,
2361 BUF_SIZE = 200
2362 };
Lee Thomason624d43f2012-10-12 10:58:48 -07002363 bool _entityFlag[ENTITY_RANGE];
2364 bool _restrictedEntityFlag[ENTITY_RANGE];
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002365
Lee Thomason624d43f2012-10-12 10:58:48 -07002366 DynArray< char, 20 > _buffer;
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002367
2368 // Prohibit cloning, intentionally not implemented
2369 XMLPrinter( const XMLPrinter& );
2370 XMLPrinter& operator=( const XMLPrinter& );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002371};
2372
2373
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07002374} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002375
PKEuS95060352013-07-26 10:42:44 +02002376#if defined(_MSC_VER)
2377# pragma warning(pop)
2378#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002379
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002380#endif // TINYXML2_INCLUDED