blob: 0d27eab42ded73bfe895960ddfe303d9c2150d01 [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
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
orbitcowboy0e7f2892019-01-15 11:28:49 +010048 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070049 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
orbitcowboy0e7f2892019-01-15 11:28:49 +010055 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070056 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100200 const char endChar = *endTag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 // Inner loop of text parsing.
204 while ( *p ) {
205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
206 Set( start, p, strFlags );
207 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000208 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000209 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 }
211 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300212 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 }
214 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215}
216
217
218char* StrPair::ParseName( char* p )
219{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 return 0;
222 }
JayXonee525db2014-12-24 04:01:42 -0500223 if ( !XMLUtil::IsNameStartChar( *p ) ) {
224 return 0;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400227 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500228 ++p;
229 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 ++p;
231 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800232
JayXonee525db2014-12-24 04:01:42 -0500233 Set( start, p, 0 );
234 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235}
236
237
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238void StrPair::CollapseWhitespace()
239{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400240 // Adjusting _start would cause undefined behavior on delete[]
241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300245 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300246 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700248
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700249 while( *p ) {
250 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800251 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 if ( *p == 0 ) {
253 break; // don't write to q; this trims the trailing space.
254 }
255 *q = ' ';
256 ++q;
257 }
258 *q = *p;
259 ++q;
260 ++p;
261 }
262 *q = 0;
263 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700264}
265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267const char* StrPair::GetStr()
268{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300269 TIXMLASSERT( _start );
270 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags & NEEDS_FLUSH ) {
272 *_end = 0;
273 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300276 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700277 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800278
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 while( p < _end ) {
280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 // CR-LF pair becomes LF
282 // CR alone becomes LF
283 // LF-CR becomes LF
284 if ( *(p+1) == LF ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300290 *q = LF;
291 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 if ( *(p+1) == CR ) {
295 p += 2;
296 }
297 else {
298 ++p;
299 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300300 *q = LF;
301 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 // Entities handled by tinyXML2:
305 // - special entities in the entity table [in/out]
306 // - numeric character reference [in]
307 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400310 const int buflen = 10;
311 char buf[buflen] = { 0 };
312 int len = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100313 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me6f51c802015-03-14 13:25:03 +0300314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
448 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
Lee Thomason51c12712016-06-04 20:18:49 -0700585void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
591
Lee Thomason21be8822012-07-15 17:27:22 -0700592bool XMLUtil::ToInt( const char* str, int* value )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608bool XMLUtil::ToBool( const char* str, bool* value )
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 int ival = 0;
611 if ( ToInt( str, &ival )) {
612 *value = (ival==0) ? false : true;
613 return true;
614 }
615 if ( StringEqual( str, "true" ) ) {
616 *value = true;
617 return true;
618 }
619 else if ( StringEqual( str, "false" ) ) {
620 *value = false;
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
627bool XMLUtil::ToFloat( const char* str, float* value )
628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
630 return true;
631 }
632 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700633}
634
Lee Thomason51c12712016-06-04 20:18:49 -0700635
Lee Thomason21be8822012-07-15 17:27:22 -0700636bool XMLUtil::ToDouble( const char* str, double* value )
637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
639 return true;
640 }
641 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700642}
643
644
Lee Thomason51c12712016-06-04 20:18:49 -0700645bool XMLUtil::ToInt64(const char* str, int64_t* value)
646{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700647 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
648 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
649 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700650 return true;
651 }
652 return false;
653}
654
655
cugone75a5acc2019-04-11 22:03:43 -0500656bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
657 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
658 if(TIXML_SSCANF(str, "%llu", &v) == 1) {
659 *value = (uint64_t)v;
660 return true;
661 }
662 return false;
663}
664
665
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700666char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667{
Dmitry-Me02384662015-03-03 16:02:13 +0300668 TIXMLASSERT( node );
669 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400670 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000671 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000672 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300673 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300674 *node = 0;
675 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 return p;
677 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678
Dmitry-Me962083b2015-05-26 11:38:30 +0300679 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 static const char* xmlHeader = { "<?" };
681 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300683 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800685
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 static const int xmlHeaderLen = 2;
687 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300689 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800691
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
693 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400694 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300696 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000697 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 p += xmlHeaderLen;
699 }
700 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300701 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000702 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 p += commentHeaderLen;
704 }
705 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300706 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p += cdataHeaderLen;
710 text->SetCData( true );
711 }
712 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p += dtdHeaderLen;
716 }
717 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300718 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000719 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 p += elementHeaderLen;
721 }
722 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300723 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000724 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000726 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728
Dmitry-Me02384662015-03-03 16:02:13 +0300729 TIXMLASSERT( returnNode );
730 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 *node = returnNode;
732 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733}
734
735
Lee Thomason751da522012-02-10 08:50:51 -0800736bool XMLDocument::Accept( XMLVisitor* visitor ) const
737{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300738 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 if ( visitor->VisitEnter( *this ) ) {
740 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
741 if ( !node->Accept( visitor ) ) {
742 break;
743 }
744 }
745 }
746 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800747}
Lee Thomason56bdd022012-02-09 18:16:58 -0800748
749
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750// --------- XMLNode ----------- //
751
752XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _document( doc ),
754 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200755 _value(),
kezenatorec694152016-11-26 17:21:43 +1000756 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200758 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700759 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200760 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800761{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800762}
763
764
765XMLNode::~XMLNode()
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 if ( _parent ) {
769 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800771}
772
Gumichan010f1fa6d2018-02-01 14:16:24 +0100773const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200774{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300775 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530776 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530777 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200778 return _value.GetStr();
779}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800780
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800781void XMLNode::SetValue( const char* str, bool staticMem )
782{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 }
786 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800789}
790
Dmitry-Me3f63f212017-06-19 18:25:19 +0300791XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700792{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300793 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700794 if (!clone) return 0;
795
796 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300797 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700798 TIXMLASSERT(childClone);
799 clone->InsertEndChild(childClone);
800 }
801 return clone;
802}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800803
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800804void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800805{
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300807 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300808 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800811}
812
813
814void XMLNode::Unlink( XMLNode* child )
815{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300816 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300817 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300818 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 if ( child == _firstChild ) {
820 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 if ( child == _lastChild ) {
823 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 }
Lee Thomasond923c672012-01-23 08:44:25 -0800825
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 if ( child->_prev ) {
827 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 if ( child->_next ) {
830 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
Lee Thomason8a763612017-06-16 09:30:16 -0700832 child->_next = 0;
833 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700834 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800835}
836
837
U-Stream\Leeae25a442012-02-17 17:48:16 -0800838void XMLNode::DeleteChild( XMLNode* node )
839{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300840 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300841 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100843 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700844 TIXMLASSERT(node->_prev == 0);
845 TIXMLASSERT(node->_next == 0);
846 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400847 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800848}
849
850
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800851XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
852{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300853 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300854 if ( addThis->_document != _document ) {
855 TIXMLASSERT( false );
856 return 0;
857 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800858 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700859
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 if ( _lastChild ) {
861 TIXMLASSERT( _firstChild );
862 TIXMLASSERT( _lastChild->_next == 0 );
863 _lastChild->_next = addThis;
864 addThis->_prev = _lastChild;
865 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800866
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 }
869 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 TIXMLASSERT( _firstChild == 0 );
871 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800872
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 addThis->_prev = 0;
874 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800878}
879
880
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
882{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300883 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300884 if ( addThis->_document != _document ) {
885 TIXMLASSERT( false );
886 return 0;
887 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800888 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700889
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 if ( _firstChild ) {
891 TIXMLASSERT( _lastChild );
892 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _firstChild->_prev = addThis;
895 addThis->_next = _firstChild;
896 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800897
Lee Thomason624d43f2012-10-12 10:58:48 -0700898 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 }
900 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700901 TIXMLASSERT( _lastChild == 0 );
902 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800903
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 addThis->_prev = 0;
905 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700907 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400908 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800909}
910
911
912XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
913{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300914 TIXMLASSERT( addThis );
915 if ( addThis->_document != _document ) {
916 TIXMLASSERT( false );
917 return 0;
918 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700919
Dmitry-Meabb2d042014-12-09 12:59:31 +0300920 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700921
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300923 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 return 0;
925 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300926 if ( afterThis == addThis ) {
927 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
928 // Now AddThis must disappear from it's location and then
929 // reappear between BeforeThis and OneAfterAddThis.
930 // So just leave it where it is.
931 return addThis;
932 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 // The last node or the only node.
936 return InsertEndChild( addThis );
937 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800938 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700939 addThis->_prev = afterThis;
940 addThis->_next = afterThis->_next;
941 afterThis->_next->_prev = addThis;
942 afterThis->_next = addThis;
943 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800945}
946
947
948
949
Dmitry-Me886ad972015-07-22 11:00:51 +0300950const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800951{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300952 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300953 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300955 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 }
958 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800959}
960
961
Dmitry-Me886ad972015-07-22 11:00:51 +0300962const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800963{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300964 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300965 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 }
970 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800971}
972
973
Dmitry-Me886ad972015-07-22 11:00:51 +0300974const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800975{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300976 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300977 const XMLElement* element = node->ToElementWithName( name );
978 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400979 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 }
982 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800983}
984
985
Dmitry-Me886ad972015-07-22 11:00:51 +0300986const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300988 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300989 const XMLElement* element = node->ToElementWithName( name );
990 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400991 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
993 }
994 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995}
996
997
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300998char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 // This is a recursive method, but thinking about it "at the current level"
1001 // it is a pretty simple flat list:
1002 // <foo/>
1003 // <!-- comment -->
1004 //
1005 // With a special case:
1006 // <foo>
1007 // </foo>
1008 // <!-- comment -->
1009 //
1010 // Where the closing element (/foo) *must* be the next thing after the opening
1011 // element, and the names must match. BUT the tricky bit is that the closing
1012 // element will be read by the child.
1013 //
1014 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1015 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001016
Lee Thomasond946dda2018-04-05 09:11:08 -07001017 XMLDocument::DepthTracker tracker(_document);
1018 if (_document->Error())
1019 return 0;
1020
1021 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001023
Lee Thomason624d43f2012-10-12 10:58:48 -07001024 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001025 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001026 if ( node == 0 ) {
1027 break;
1028 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001029
orbitcowboy0e7f2892019-01-15 11:28:49 +01001030 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001031
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001033 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001035 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001037 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 break;
1040 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041
orbitcowboy0e7f2892019-01-15 11:28:49 +01001042 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301043 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001044 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001045 //
1046 // Multiple declarations are allowed but all declarations
1047 // must occur before anything else.
1048 //
1049 // Optimized due to a security test case. If the first node is
1050 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001051 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001052 bool wellLocated = false;
1053
1054 if (ToDocument()) {
1055 if (FirstChild()) {
1056 wellLocated =
1057 FirstChild() &&
1058 FirstChild()->ToDeclaration() &&
1059 LastChild() &&
1060 LastChild()->ToDeclaration();
1061 }
1062 else {
1063 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301064 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001065 }
1066 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001067 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001068 DeleteNode( node );
1069 break;
1070 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301071 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301072
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001073 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001075 // We read the end tag. Return it to the parent.
1076 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001077 if ( parentEndTag ) {
1078 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001079 }
1080 node->_memPool->SetTracked(); // created and then immediately deleted.
1081 DeleteNode( node );
1082 return p;
1083 }
1084
1085 // Handle an end tag returned to this level.
1086 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001087 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001088 if ( endTag.Empty() ) {
1089 if ( ele->ClosingType() == XMLElement::OPEN ) {
1090 mismatch = true;
1091 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001093 else {
1094 if ( ele->ClosingType() != XMLElement::OPEN ) {
1095 mismatch = true;
1096 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001097 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001098 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 }
1100 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001101 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001102 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001103 DeleteNode( node );
1104 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001105 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 }
JayXondbfdd8f2014-12-12 20:07:14 -05001107 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 }
1109 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001110}
1111
Lee Thomason816d3fa2017-06-05 14:35:55 -07001112/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001113{
1114 if ( node == 0 ) {
1115 return;
1116 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001117 TIXMLASSERT(node->_document);
1118 if (!node->ToDocument()) {
1119 node->_document->MarkInUse(node);
1120 }
1121
Dmitry-Mee3225b12014-09-03 11:03:11 +04001122 MemPool* pool = node->_memPool;
1123 node->~XMLNode();
1124 pool->Free( node );
1125}
1126
Lee Thomason3cebdc42015-01-05 17:16:28 -08001127void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001128{
1129 TIXMLASSERT( insertThis );
1130 TIXMLASSERT( insertThis->_document == _document );
1131
Lee Thomason816d3fa2017-06-05 14:35:55 -07001132 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001133 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001134 }
1135 else {
1136 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001137 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001138 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001139}
1140
Dmitry-Meecb9b072016-10-12 16:44:59 +03001141const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1142{
1143 const XMLElement* element = this->ToElement();
1144 if ( element == 0 ) {
1145 return 0;
1146 }
1147 if ( name == 0 ) {
1148 return element;
1149 }
1150 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1151 return element;
1152 }
1153 return 0;
1154}
1155
Lee Thomason5492a1c2012-01-23 15:32:10 -08001156// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001157char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001160 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001162 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 }
1164 return p;
1165 }
1166 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1168 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001169 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001171
kezenator4f756162016-11-29 19:46:27 +10001172 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( p && *p ) {
1174 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001175 }
1176 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001177 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
1179 }
1180 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001181}
1182
1183
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001184XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 }
1189 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1190 text->SetCData( this->CData() );
1191 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001192}
1193
1194
1195bool XMLText::ShallowEqual( const XMLNode* compare ) const
1196{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001197 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001198 const XMLText* text = compare->ToText();
1199 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001200}
1201
1202
Lee Thomason56bdd022012-02-09 18:16:58 -08001203bool XMLText::Accept( XMLVisitor* visitor ) const
1204{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001205 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001207}
1208
1209
Lee Thomason3f57d272012-01-11 15:30:03 -08001210// --------- XMLComment ---------- //
1211
Lee Thomasone4422302012-01-20 17:59:50 -08001212XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001213{
1214}
1215
1216
Lee Thomasonce0763e2012-01-11 15:43:54 -08001217XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001218{
Lee Thomason3f57d272012-01-11 15:30:03 -08001219}
1220
1221
kezenator4f756162016-11-29 19:46:27 +10001222char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001225 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001227 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 }
1229 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001230}
1231
1232
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001233XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 }
1238 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1239 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001240}
1241
1242
1243bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001245 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001246 const XMLComment* comment = compare->ToComment();
1247 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248}
1249
1250
Lee Thomason751da522012-02-10 08:50:51 -08001251bool XMLComment::Accept( XMLVisitor* visitor ) const
1252{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001253 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001255}
Lee Thomason56bdd022012-02-09 18:16:58 -08001256
1257
Lee Thomason50f97b22012-02-11 16:33:40 -08001258// --------- XMLDeclaration ---------- //
1259
1260XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1261{
1262}
1263
1264
1265XMLDeclaration::~XMLDeclaration()
1266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001268}
1269
1270
kezenator4f756162016-11-29 19:46:27 +10001271char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001274 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001276 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 }
1278 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001279}
1280
1281
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001282XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001285 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 }
1287 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1288 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001289}
1290
1291
1292bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1293{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001294 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001295 const XMLDeclaration* declaration = compare->ToDeclaration();
1296 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001297}
1298
1299
1300
Lee Thomason50f97b22012-02-11 16:33:40 -08001301bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1302{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001303 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001305}
1306
1307// --------- XMLUnknown ---------- //
1308
1309XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1310{
1311}
1312
1313
1314XMLUnknown::~XMLUnknown()
1315{
1316}
1317
1318
kezenator4f756162016-11-29 19:46:27 +10001319char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001322 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001324 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001325 }
1326 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001327}
1328
1329
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001330XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001333 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 }
1335 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1336 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001337}
1338
1339
1340bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1341{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001342 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001343 const XMLUnknown* unknown = compare->ToUnknown();
1344 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001345}
1346
1347
Lee Thomason50f97b22012-02-11 16:33:40 -08001348bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1349{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001350 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001352}
1353
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001354// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001355
Gumichan010f1fa6d2018-02-01 14:16:24 +01001356const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001357{
1358 return _name.GetStr();
1359}
1360
Gumichan010f1fa6d2018-02-01 14:16:24 +01001361const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001362{
1363 return _value.GetStr();
1364}
1365
kezenator4f756162016-11-29 19:46:27 +10001366char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( !p || !*p ) {
1371 return 0;
1372 }
Lee Thomason22aead12012-01-23 13:29:35 -08001373
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001375 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001376 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 return 0;
1378 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001379
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001381 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( *p != '\"' && *p != '\'' ) {
1383 return 0;
1384 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001385
orbitcowboy0e7f2892019-01-15 11:28:49 +01001386 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001388
kezenator4f756162016-11-29 19:46:27 +10001389 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001391}
1392
1393
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001394void XMLAttribute::SetName( const char* n )
1395{
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001397}
1398
1399
Lee Thomason2fa81722012-11-09 12:37:46 -08001400XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001403 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001406}
1407
1408
Lee Thomason2fa81722012-11-09 12:37:46 -08001409XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001412 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 }
1414 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001415}
1416
1417
Lee Thomason51c12712016-06-04 20:18:49 -07001418XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1419{
1420 if (XMLUtil::ToInt64(Value(), value)) {
1421 return XML_SUCCESS;
1422 }
1423 return XML_WRONG_ATTRIBUTE_TYPE;
1424}
1425
1426
cugone75a5acc2019-04-11 22:03:43 -05001427XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1428{
1429 if(XMLUtil::ToUnsigned64(Value(), value)) {
1430 return XML_SUCCESS;
1431 }
1432 return XML_WRONG_ATTRIBUTE_TYPE;
1433}
1434
1435
Lee Thomason2fa81722012-11-09 12:37:46 -08001436XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001439 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001442}
1443
1444
Lee Thomason2fa81722012-11-09 12:37:46 -08001445XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001448 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 }
1450 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001451}
1452
1453
Lee Thomason2fa81722012-11-09 12:37:46 -08001454XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001457 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001460}
1461
1462
1463void XMLAttribute::SetAttribute( const char* v )
1464{
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001466}
1467
1468
Lee Thomason1ff38e02012-02-14 18:18:16 -08001469void XMLAttribute::SetAttribute( int v )
1470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 char buf[BUF_SIZE];
1472 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001474}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001475
1476
1477void XMLAttribute::SetAttribute( unsigned v )
1478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 char buf[BUF_SIZE];
1480 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001482}
1483
1484
Lee Thomason51c12712016-06-04 20:18:49 -07001485void XMLAttribute::SetAttribute(int64_t v)
1486{
1487 char buf[BUF_SIZE];
1488 XMLUtil::ToStr(v, buf, BUF_SIZE);
1489 _value.SetStr(buf);
1490}
1491
1492
1493
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494void XMLAttribute::SetAttribute( bool v )
1495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 char buf[BUF_SIZE];
1497 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001499}
1500
1501void XMLAttribute::SetAttribute( double v )
1502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 char buf[BUF_SIZE];
1504 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001506}
1507
1508void XMLAttribute::SetAttribute( float v )
1509{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 char buf[BUF_SIZE];
1511 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001513}
1514
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001515
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001516// --------- XMLElement ---------- //
1517XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001518 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001520{
1521}
1522
1523
1524XMLElement::~XMLElement()
1525{
Lee Thomason624d43f2012-10-12 10:58:48 -07001526 while( _rootAttribute ) {
1527 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001528 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001529 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001531}
1532
1533
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001534const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1535{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001536 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1538 return a;
1539 }
1540 }
1541 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001542}
1543
1544
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001545const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 const XMLAttribute* a = FindAttribute( name );
1548 if ( !a ) {
1549 return 0;
1550 }
1551 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1552 return a->Value();
1553 }
1554 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001555}
1556
Gumichan010f1fa6d2018-02-01 14:16:24 +01001557int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001558{
1559 int i = defaultValue;
1560 QueryIntAttribute(name, &i);
1561 return i;
1562}
1563
Gumichan010f1fa6d2018-02-01 14:16:24 +01001564unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001565{
1566 unsigned i = defaultValue;
1567 QueryUnsignedAttribute(name, &i);
1568 return i;
1569}
1570
Gumichan010f1fa6d2018-02-01 14:16:24 +01001571int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001572{
1573 int64_t i = defaultValue;
1574 QueryInt64Attribute(name, &i);
1575 return i;
1576}
1577
Gumichan010f1fa6d2018-02-01 14:16:24 +01001578bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001579{
1580 bool b = defaultValue;
1581 QueryBoolAttribute(name, &b);
1582 return b;
1583}
1584
Gumichan010f1fa6d2018-02-01 14:16:24 +01001585double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001586{
1587 double d = defaultValue;
1588 QueryDoubleAttribute(name, &d);
1589 return d;
1590}
1591
Gumichan010f1fa6d2018-02-01 14:16:24 +01001592float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001593{
1594 float f = defaultValue;
1595 QueryFloatAttribute(name, &f);
1596 return f;
1597}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001598
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001599const char* XMLElement::GetText() const
1600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001602 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 }
1604 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001605}
1606
1607
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001608void XMLElement::SetText( const char* inText )
1609{
Uli Kusterer869bb592014-01-21 01:36:16 +01001610 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001611 FirstChild()->SetValue( inText );
1612 else {
1613 XMLText* theText = GetDocument()->NewText( inText );
1614 InsertFirstChild( theText );
1615 }
1616}
1617
Lee Thomason5bb2d802014-01-24 10:42:57 -08001618
Gumichan010f1fa6d2018-02-01 14:16:24 +01001619void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001620{
1621 char buf[BUF_SIZE];
1622 XMLUtil::ToStr( v, buf, BUF_SIZE );
1623 SetText( buf );
1624}
1625
1626
Gumichan010f1fa6d2018-02-01 14:16:24 +01001627void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001628{
1629 char buf[BUF_SIZE];
1630 XMLUtil::ToStr( v, buf, BUF_SIZE );
1631 SetText( buf );
1632}
1633
1634
Lee Thomason51c12712016-06-04 20:18:49 -07001635void XMLElement::SetText(int64_t v)
1636{
1637 char buf[BUF_SIZE];
1638 XMLUtil::ToStr(v, buf, BUF_SIZE);
1639 SetText(buf);
1640}
1641
1642
1643void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001644{
1645 char buf[BUF_SIZE];
1646 XMLUtil::ToStr( v, buf, BUF_SIZE );
1647 SetText( buf );
1648}
1649
1650
Gumichan010f1fa6d2018-02-01 14:16:24 +01001651void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001652{
1653 char buf[BUF_SIZE];
1654 XMLUtil::ToStr( v, buf, BUF_SIZE );
1655 SetText( buf );
1656}
1657
1658
Gumichan010f1fa6d2018-02-01 14:16:24 +01001659void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001660{
1661 char buf[BUF_SIZE];
1662 XMLUtil::ToStr( v, buf, BUF_SIZE );
1663 SetText( buf );
1664}
1665
1666
MortenMacFly4ee49f12013-01-14 20:03:14 +01001667XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001668{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001670 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001671 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 return XML_SUCCESS;
1673 }
1674 return XML_CAN_NOT_CONVERT_TEXT;
1675 }
1676 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001677}
1678
1679
MortenMacFly4ee49f12013-01-14 20:03:14 +01001680XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001681{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001683 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001684 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 return XML_SUCCESS;
1686 }
1687 return XML_CAN_NOT_CONVERT_TEXT;
1688 }
1689 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001690}
1691
1692
Lee Thomason51c12712016-06-04 20:18:49 -07001693XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1694{
1695 if (FirstChild() && FirstChild()->ToText()) {
1696 const char* t = FirstChild()->Value();
1697 if (XMLUtil::ToInt64(t, ival)) {
1698 return XML_SUCCESS;
1699 }
1700 return XML_CAN_NOT_CONVERT_TEXT;
1701 }
1702 return XML_NO_TEXT_NODE;
1703}
1704
1705
MortenMacFly4ee49f12013-01-14 20:03:14 +01001706XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001707{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001709 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001710 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 return XML_SUCCESS;
1712 }
1713 return XML_CAN_NOT_CONVERT_TEXT;
1714 }
1715 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001716}
1717
1718
MortenMacFly4ee49f12013-01-14 20:03:14 +01001719XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001722 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001723 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 return XML_SUCCESS;
1725 }
1726 return XML_CAN_NOT_CONVERT_TEXT;
1727 }
1728 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001729}
1730
1731
MortenMacFly4ee49f12013-01-14 20:03:14 +01001732XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001735 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001736 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 return XML_SUCCESS;
1738 }
1739 return XML_CAN_NOT_CONVERT_TEXT;
1740 }
1741 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001742}
1743
Josh Wittnercf3dd092016-10-11 18:57:17 -07001744int XMLElement::IntText(int defaultValue) const
1745{
1746 int i = defaultValue;
1747 QueryIntText(&i);
1748 return i;
1749}
1750
1751unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1752{
1753 unsigned i = defaultValue;
1754 QueryUnsignedText(&i);
1755 return i;
1756}
1757
1758int64_t XMLElement::Int64Text(int64_t defaultValue) const
1759{
1760 int64_t i = defaultValue;
1761 QueryInt64Text(&i);
1762 return i;
1763}
1764
1765bool XMLElement::BoolText(bool defaultValue) const
1766{
1767 bool b = defaultValue;
1768 QueryBoolText(&b);
1769 return b;
1770}
1771
1772double XMLElement::DoubleText(double defaultValue) const
1773{
1774 double d = defaultValue;
1775 QueryDoubleText(&d);
1776 return d;
1777}
1778
1779float XMLElement::FloatText(float defaultValue) const
1780{
1781 float f = defaultValue;
1782 QueryFloatText(&f);
1783 return f;
1784}
Lee Thomason21be8822012-07-15 17:27:22 -07001785
1786
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001787XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1788{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 XMLAttribute* last = 0;
1790 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1795 break;
1796 }
1797 }
1798 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001799 attrib = CreateAttribute();
1800 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001802 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001803 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 }
1805 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001806 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001807 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 }
1809 attrib->SetName( name );
1810 }
1811 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001812}
1813
1814
U-Stream\Leeae25a442012-02-17 17:48:16 -08001815void XMLElement::DeleteAttribute( const char* name )
1816{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1820 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
1823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001826 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 break;
1828 }
1829 prev = a;
1830 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001831}
1832
1833
kezenator4f756162016-11-29 19:46:27 +10001834char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001835{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001837
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 // Read the attributes.
1839 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001840 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001841 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001842 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 return 0;
1844 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001845
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001847 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001848 XMLAttribute* attrib = CreateAttribute();
1849 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001850 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001851
orbitcowboy0e7f2892019-01-15 11:28:49 +01001852 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001853
kezenator4f756162016-11-29 19:46:27 +10001854 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001856 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001857 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 return 0;
1859 }
1860 // There is a minor bug here: if the attribute in the source xml
1861 // document is duplicated, it will not be detected and the
1862 // attribute will be doubly added. However, tracking the 'prevAttribute'
1863 // avoids re-scanning the attribute list. Preferring performance for
1864 // now, may reconsider in the future.
1865 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001866 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 }
1869 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001870 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 }
1873 prevAttribute = attrib;
1874 }
1875 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 else if ( *p == '>' ) {
1877 ++p;
1878 break;
1879 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001880 // end of the tag
1881 else if ( *p == '/' && *(p+1) == '>' ) {
1882 _closingType = CLOSED;
1883 return p+2; // done; sealed element.
1884 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001886 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 return 0;
1888 }
1889 }
1890 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001891}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001892
Dmitry-Mee3225b12014-09-03 11:03:11 +04001893void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1894{
1895 if ( attribute == 0 ) {
1896 return;
1897 }
1898 MemPool* pool = attribute->_memPool;
1899 attribute->~XMLAttribute();
1900 pool->Free( attribute );
1901}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001902
Dmitry-Mea60caa22016-11-22 18:28:08 +03001903XMLAttribute* XMLElement::CreateAttribute()
1904{
1905 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1906 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001907 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001908 attrib->_memPool = &_document->_attributePool;
1909 attrib->_memPool->SetTracked();
1910 return attrib;
1911}
1912
Lee Thomason67d61312012-01-24 16:01:51 -08001913//
1914// <ele></ele>
1915// <ele>foo<b>bar</b></ele>
1916//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001917char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001920 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001921
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 // The closing element is the </element> form. It is
1923 // parsed just like a regular element then deleted from
1924 // the DOM.
1925 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 ++p;
1928 }
Lee Thomason67d61312012-01-24 16:01:51 -08001929
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 p = _value.ParseName( p );
1931 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 return 0;
1933 }
Lee Thomason67d61312012-01-24 16:01:51 -08001934
kezenator4f756162016-11-29 19:46:27 +10001935 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001936 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 return p;
1938 }
Lee Thomason67d61312012-01-24 16:01:51 -08001939
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001940 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001942}
1943
1944
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001945
1946XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 }
1951 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1952 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1953 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1954 }
1955 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001956}
1957
1958
1959bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1960{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001961 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001963 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001964
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 const XMLAttribute* a=FirstAttribute();
1966 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001967
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 while ( a && b ) {
1969 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1970 return false;
1971 }
1972 a = a->Next();
1973 b = b->Next();
1974 }
1975 if ( a || b ) {
1976 // different count
1977 return false;
1978 }
1979 return true;
1980 }
1981 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001982}
1983
1984
Lee Thomason751da522012-02-10 08:50:51 -08001985bool XMLElement::Accept( XMLVisitor* visitor ) const
1986{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001987 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1990 if ( !node->Accept( visitor ) ) {
1991 break;
1992 }
1993 }
1994 }
1995 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001996}
Lee Thomason56bdd022012-02-09 18:16:58 -08001997
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001998
Lee Thomason3f57d272012-01-11 15:30:03 -08001999// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002000
2001// Warning: List must match 'enum XMLError'
2002const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2003 "XML_SUCCESS",
2004 "XML_NO_ATTRIBUTE",
2005 "XML_WRONG_ATTRIBUTE_TYPE",
2006 "XML_ERROR_FILE_NOT_FOUND",
2007 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2008 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002009 "XML_ERROR_PARSING_ELEMENT",
2010 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002011 "XML_ERROR_PARSING_TEXT",
2012 "XML_ERROR_PARSING_CDATA",
2013 "XML_ERROR_PARSING_COMMENT",
2014 "XML_ERROR_PARSING_DECLARATION",
2015 "XML_ERROR_PARSING_UNKNOWN",
2016 "XML_ERROR_EMPTY_DOCUMENT",
2017 "XML_ERROR_MISMATCHED_ELEMENT",
2018 "XML_ERROR_PARSING",
2019 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002020 "XML_NO_TEXT_NODE",
2021 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002022};
2023
2024
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002025XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _writeBOM( false ),
2028 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002029 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002030 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002031 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002032 _errorLineNum( 0 ),
2033 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002034 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002035 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002036 _unlinked(),
2037 _elementPool(),
2038 _attributePool(),
2039 _textPool(),
2040 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002041{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002042 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2043 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002044}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002045
2046
Lee Thomason3f57d272012-01-11 15:30:03 -08002047XMLDocument::~XMLDocument()
2048{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002049 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002050}
2051
2052
Lee Thomason816d3fa2017-06-05 14:35:55 -07002053void XMLDocument::MarkInUse(XMLNode* node)
2054{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002055 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002056 TIXMLASSERT(node->_parent == 0);
2057
2058 for (int i = 0; i < _unlinked.Size(); ++i) {
2059 if (node == _unlinked[i]) {
2060 _unlinked.SwapRemove(i);
2061 break;
2062 }
2063 }
2064}
2065
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002066void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002067{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002068 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002069 while( _unlinked.Size()) {
2070 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2071 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002072
Peter Matula50689912018-01-09 12:52:26 +01002073#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002074 const bool hadError = Error();
2075#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002076 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002077
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 delete [] _charBuffer;
2079 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002080 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002081
2082#if 0
2083 _textPool.Trace( "text" );
2084 _elementPool.Trace( "element" );
2085 _commentPool.Trace( "comment" );
2086 _attributePool.Trace( "attribute" );
2087#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002088
Peter Matula50689912018-01-09 12:52:26 +01002089#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002090 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002091 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2092 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2093 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2094 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2095 }
2096#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002097}
2098
Lee Thomason3f57d272012-01-11 15:30:03 -08002099
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002100void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002101{
2102 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002103 if (target == this) {
2104 return; // technically success - a no-op.
2105 }
Lee Thomason7085f002017-06-01 18:09:43 -07002106
2107 target->Clear();
2108 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2109 target->InsertEndChild(node->DeepClone(target));
2110 }
2111}
2112
Lee Thomason2c85a712012-01-31 08:24:24 -08002113XMLElement* XMLDocument::NewElement( const char* name )
2114{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002115 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 ele->SetName( name );
2117 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002118}
2119
2120
Lee Thomason1ff38e02012-02-14 18:18:16 -08002121XMLComment* XMLDocument::NewComment( const char* str )
2122{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002123 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 comment->SetValue( str );
2125 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002126}
2127
2128
2129XMLText* XMLDocument::NewText( const char* str )
2130{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002131 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 text->SetValue( str );
2133 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002134}
2135
2136
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002137XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2138{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002139 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2141 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002142}
2143
2144
2145XMLUnknown* XMLDocument::NewUnknown( const char* str )
2146{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002147 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 unk->SetValue( str );
2149 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002150}
2151
Dmitry-Me01578db2014-08-19 10:18:48 +04002152static FILE* callfopen( const char* filepath, const char* mode )
2153{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002154 TIXMLASSERT( filepath );
2155 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002156#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2157 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002158 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002159 if ( err ) {
2160 return 0;
2161 }
2162#else
2163 FILE* fp = fopen( filepath, mode );
2164#endif
2165 return fp;
2166}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002167
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002168void XMLDocument::DeleteNode( XMLNode* node ) {
2169 TIXMLASSERT( node );
2170 TIXMLASSERT(node->_document == this );
2171 if (node->_parent) {
2172 node->_parent->DeleteChild( node );
2173 }
2174 else {
2175 // Isn't in the tree.
2176 // Use the parent delete.
2177 // Also, we need to mark it tracked: we 'know'
2178 // it was never used.
2179 node->_memPool->SetTracked();
2180 // Call the static XMLNode version:
2181 XMLNode::DeleteNode(node);
2182 }
2183}
2184
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002185
Lee Thomason2fa81722012-11-09 12:37:46 -08002186XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002188 if ( !filename ) {
2189 TIXMLASSERT( false );
2190 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2191 return _errorID;
2192 }
2193
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002194 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002195 FILE* fp = callfopen( filename, "rb" );
2196 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002197 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002198 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 }
2200 LoadFile( fp );
2201 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002203}
2204
Dmitry-Me901fed52015-09-25 10:29:51 +03002205// This is likely overengineered template art to have a check that unsigned long value incremented
2206// by one still fits into size_t. If size_t type is larger than unsigned long type
2207// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2208// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2209// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2210// types sizes relate to each other.
2211template
2212<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2213struct LongFitsIntoSizeTMinusOne {
2214 static bool Fits( unsigned long value )
2215 {
2216 return value < (size_t)-1;
2217 }
2218};
2219
2220template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002221struct LongFitsIntoSizeTMinusOne<false> {
2222 static bool Fits( unsigned long )
2223 {
2224 return true;
2225 }
2226};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227
Lee Thomason2fa81722012-11-09 12:37:46 -08002228XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002230 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002232 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002233 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002234 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002235 return _errorID;
2236 }
2237
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002239 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002241 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002242 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002243 return _errorID;
2244 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002245 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246
Dmitry-Me901fed52015-09-25 10:29:51 +03002247 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002248 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002249 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002250 return _errorID;
2251 }
2252
Dmitry-Me72801b82015-05-07 09:41:39 +03002253 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002254 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002257
Dmitry-Me72801b82015-05-07 09:41:39 +03002258 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002259 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002260 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002261 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002263 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002264 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002266
Lee Thomason624d43f2012-10-12 10:58:48 -07002267 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002268
Dmitry-Me97476b72015-01-01 16:15:57 +03002269 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002271}
2272
2273
Lee Thomason2fa81722012-11-09 12:37:46 -08002274XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002275{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002276 if ( !filename ) {
2277 TIXMLASSERT( false );
2278 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2279 return _errorID;
2280 }
2281
Dmitry-Me01578db2014-08-19 10:18:48 +04002282 FILE* fp = callfopen( filename, "w" );
2283 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002284 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 }
2287 SaveFile(fp, compact);
2288 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002290}
2291
2292
Lee Thomason2fa81722012-11-09 12:37:46 -08002293XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002294{
Ant Mitchell189198f2015-03-24 16:20:36 +00002295 // Clear any error from the last save, otherwise it will get reported
2296 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002297 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 XMLPrinter stream( fp, compact );
2299 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301}
2302
Lee Thomason1ff38e02012-02-14 18:18:16 -08002303
Lee Thomason2fa81722012-11-09 12:37:46 -08002304XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002305{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002306 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002307
Lee Thomason82d32002014-02-21 22:47:18 -08002308 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002309 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 }
2312 if ( len == (size_t)(-1) ) {
2313 len = strlen( p );
2314 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002315 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002316 _charBuffer = new char[ len+1 ];
2317 memcpy( _charBuffer, p, len );
2318 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002319
Dmitry-Me97476b72015-01-01 16:15:57 +03002320 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002321 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002322 // clean up now essentially dangling memory.
2323 // and the parse fail can put objects in the
2324 // pools that are dead and inaccessible.
2325 DeleteChildren();
2326 _elementPool.Clear();
2327 _attributePool.Clear();
2328 _textPool.Clear();
2329 _commentPool.Clear();
2330 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002331 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002332}
2333
2334
PKEuS1c5f99e2013-07-06 11:28:39 +02002335void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002336{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002337 if ( streamer ) {
2338 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002340 else {
2341 XMLPrinter stdoutStreamer( stdout );
2342 Accept( &stdoutStreamer );
2343 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002344}
2345
2346
Lee Thomasonaa188392017-09-19 17:54:31 -07002347void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002348{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002349 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002350 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002351 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002352 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002353
orbitcowboy0e7f2892019-01-15 11:28:49 +01002354 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002355 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002356
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002357 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002358 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
Lee Thomasonaa188392017-09-19 17:54:31 -07002359
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002360 if (format) {
2361 size_t len = strlen(buffer);
2362 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2363 len = strlen(buffer);
2364
2365 va_list va;
2366 va_start(va, format);
2367 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2368 va_end(va);
2369 }
2370 _errorStr.SetStr(buffer);
2371 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002372}
2373
Lee Thomasonaa188392017-09-19 17:54:31 -07002374
Lee Thomasone90e9012016-12-24 07:34:39 -08002375/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002376{
kezenator5a700712016-11-26 13:54:42 +10002377 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2378 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002379 TIXMLASSERT( errorName && errorName[0] );
2380 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002381}
Lee Thomason5cae8972012-01-24 18:03:07 -08002382
Gumichan010f1fa6d2018-02-01 14:16:24 +01002383const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002384{
Lee Thomasonaa188392017-09-19 17:54:31 -07002385 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002386}
2387
Lee Thomasonf49b9652017-10-11 10:57:49 -07002388
2389void XMLDocument::PrintError() const
2390{
2391 printf("%s\n", ErrorStr());
2392}
2393
kezenator5a700712016-11-26 13:54:42 +10002394const char* XMLDocument::ErrorName() const
2395{
Lee Thomasone90e9012016-12-24 07:34:39 -08002396 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002397}
2398
Dmitry-Me97476b72015-01-01 16:15:57 +03002399void XMLDocument::Parse()
2400{
2401 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2402 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002403 _parseCurLineNum = 1;
2404 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002405 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002406 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002407 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002408 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002409 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002410 return;
2411 }
kezenator4f756162016-11-29 19:46:27 +10002412 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002413}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002414
Lee Thomasonf928c352018-04-05 09:24:20 -07002415void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002416{
2417 _parsingDepth++;
2418 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002419 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002420 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002421}
2422
Lee Thomasonf928c352018-04-05 09:24:20 -07002423void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002424{
2425 TIXMLASSERT(_parsingDepth > 0);
2426 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002427}
2428
PKEuS1bfb9542013-08-04 13:51:17 +02002429XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002430 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002431 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002432 _firstElement( true ),
2433 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002434 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002435 _textDepth( -1 ),
2436 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002437 _compactMode( compact ),
2438 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 _entityFlag[i] = false;
2442 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002443 }
2444 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002445 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002446 const unsigned char flagIndex = (unsigned char)entityValue;
2447 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2448 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002449 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002450 _restrictedEntityFlag[(unsigned char)'&'] = true;
2451 _restrictedEntityFlag[(unsigned char)'<'] = true;
2452 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002454}
2455
2456
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002457void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002458{
2459 va_list va;
2460 va_start( va, format );
2461
Lee Thomason624d43f2012-10-12 10:58:48 -07002462 if ( _fp ) {
2463 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 }
2465 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002466 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002467 // Close out and re-start the va-args
2468 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002469 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002471 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002472 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002473 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002475 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002476}
2477
2478
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002479void XMLPrinter::Write( const char* data, size_t size )
2480{
2481 if ( _fp ) {
2482 fwrite ( data , sizeof(char), size, _fp);
2483 }
2484 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002485 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002486 memcpy( p, data, size );
2487 p[size] = 0;
2488 }
2489}
2490
2491
2492void XMLPrinter::Putc( char ch )
2493{
2494 if ( _fp ) {
2495 fputc ( ch, _fp);
2496 }
2497 else {
2498 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2499 p[0] = ch;
2500 p[1] = 0;
2501 }
2502}
2503
2504
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002505void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002508 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002509 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002510}
2511
2512
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002513void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002514{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 // Look for runs of bytes between entities to print.
2516 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002517
Lee Thomason624d43f2012-10-12 10:58:48 -07002518 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002519 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002520 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002521 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 // Remember, char is sometimes signed. (How many times has that bitten me?)
2523 if ( *q > 0 && *q < ENTITY_RANGE ) {
2524 // Check for entities. If one is found, flush
2525 // the stream up until the entity, write the
2526 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002527 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002529 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002530 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002531 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002532 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002534 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 for( int i=0; i<NUM_ENTITIES; ++i ) {
2536 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002537 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002538 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002539 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002540 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 break;
2542 }
2543 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002544 if ( !entityPatternPrinted ) {
2545 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2546 TIXMLASSERT( false );
2547 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 ++p;
2549 }
2550 }
2551 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002552 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002553 }
Derek Quambe69ae62018-04-18 13:40:46 -05002554 // Flush the remaining string. This will be the entire
2555 // string if an entity wasn't found.
2556 if ( p < q ) {
2557 const size_t delta = q - p;
2558 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2559 Write( p, toPrint );
2560 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 }
Derek Quambe69ae62018-04-18 13:40:46 -05002562 else {
2563 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002564 }
Lee Thomason857b8682012-01-25 17:50:25 -08002565}
2566
U-Stream\Leeae25a442012-02-17 17:48:16 -08002567
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002568void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002571 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002572 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 }
2574 if ( writeDec ) {
2575 PushDeclaration( "xml version=\"1.0\"" );
2576 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002577}
2578
2579
Uli Kusterer593a33d2014-02-01 12:48:51 +01002580void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002581{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002582 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002584
Uli Kusterer593a33d2014-02-01 12:48:51 +01002585 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002586 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002587 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002588 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002589 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002590 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002591
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002592 Write ( "<" );
2593 Write ( name );
2594
Lee Thomason624d43f2012-10-12 10:58:48 -07002595 _elementJustOpened = true;
2596 _firstElement = false;
2597 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002598}
2599
2600
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002601void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002602{
Lee Thomason624d43f2012-10-12 10:58:48 -07002603 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002604 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002605 Write( name );
2606 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002607 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002608 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002609}
2610
2611
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002612void XMLPrinter::PushAttribute( const char* name, int v )
2613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002614 char buf[BUF_SIZE];
2615 XMLUtil::ToStr( v, buf, BUF_SIZE );
2616 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002617}
2618
2619
2620void XMLPrinter::PushAttribute( const char* name, unsigned v )
2621{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002622 char buf[BUF_SIZE];
2623 XMLUtil::ToStr( v, buf, BUF_SIZE );
2624 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002625}
2626
2627
Lee Thomason51c12712016-06-04 20:18:49 -07002628void XMLPrinter::PushAttribute(const char* name, int64_t v)
2629{
2630 char buf[BUF_SIZE];
2631 XMLUtil::ToStr(v, buf, BUF_SIZE);
2632 PushAttribute(name, buf);
2633}
2634
2635
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002636void XMLPrinter::PushAttribute( const char* name, bool v )
2637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002638 char buf[BUF_SIZE];
2639 XMLUtil::ToStr( v, buf, BUF_SIZE );
2640 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002641}
2642
2643
2644void XMLPrinter::PushAttribute( const char* name, double v )
2645{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002646 char buf[BUF_SIZE];
2647 XMLUtil::ToStr( v, buf, BUF_SIZE );
2648 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002649}
2650
2651
Uli Kustererca412e82014-02-01 13:35:05 +01002652void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002653{
Lee Thomason624d43f2012-10-12 10:58:48 -07002654 --_depth;
2655 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002656
Lee Thomason624d43f2012-10-12 10:58:48 -07002657 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002658 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002659 }
2660 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002661 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002662 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002665 Write ( "</" );
2666 Write ( name );
2667 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002668 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002669
Lee Thomason624d43f2012-10-12 10:58:48 -07002670 if ( _textDepth == _depth ) {
2671 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 }
Uli Kustererca412e82014-02-01 13:35:05 +01002673 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002674 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002675 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002676 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002677}
2678
2679
Dmitry-Mea092bc12014-12-23 17:57:05 +03002680void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002681{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002682 if ( !_elementJustOpened ) {
2683 return;
2684 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002685 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002686 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002687}
2688
2689
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002690void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002691{
Lee Thomason624d43f2012-10-12 10:58:48 -07002692 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002693
Dmitry-Mea092bc12014-12-23 17:57:05 +03002694 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002696 Write( "<![CDATA[" );
2697 Write( text );
2698 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002699 }
2700 else {
2701 PrintString( text, true );
2702 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002703}
2704
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002705void XMLPrinter::PushText( int64_t value )
2706{
2707 char buf[BUF_SIZE];
2708 XMLUtil::ToStr( value, buf, BUF_SIZE );
2709 PushText( buf, false );
2710}
2711
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002712void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002713{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002714 char buf[BUF_SIZE];
2715 XMLUtil::ToStr( value, buf, BUF_SIZE );
2716 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002717}
2718
2719
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002720void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002722 char buf[BUF_SIZE];
2723 XMLUtil::ToStr( value, buf, BUF_SIZE );
2724 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002725}
2726
2727
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002728void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002729{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002730 char buf[BUF_SIZE];
2731 XMLUtil::ToStr( value, buf, BUF_SIZE );
2732 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002733}
2734
2735
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002736void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002738 char buf[BUF_SIZE];
2739 XMLUtil::ToStr( value, buf, BUF_SIZE );
2740 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002741}
2742
2743
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002744void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002745{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002746 char buf[BUF_SIZE];
2747 XMLUtil::ToStr( value, buf, BUF_SIZE );
2748 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002749}
2750
Lee Thomason5cae8972012-01-24 18:03:07 -08002751
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002752void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002753{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002754 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002755 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002756 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002757 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002758 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002759 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002760
2761 Write( "<!--" );
2762 Write( comment );
2763 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002764}
Lee Thomason751da522012-02-10 08:50:51 -08002765
2766
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002767void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002768{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002769 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002770 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002771 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002772 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002773 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002774 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002775
2776 Write( "<?" );
2777 Write( value );
2778 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002779}
2780
2781
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002782void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002783{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002784 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002785 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002786 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002787 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002788 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002789 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002790
2791 Write( "<!" );
2792 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002793 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002794}
2795
2796
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002797bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002798{
Lee Thomason624d43f2012-10-12 10:58:48 -07002799 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002800 if ( doc.HasBOM() ) {
2801 PushHeader( true, false );
2802 }
2803 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002804}
2805
2806
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002807bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002808{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002809 const XMLElement* parentElem = 0;
2810 if ( element.Parent() ) {
2811 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002812 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002813 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002814 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002815 while ( attribute ) {
2816 PushAttribute( attribute->Name(), attribute->Value() );
2817 attribute = attribute->Next();
2818 }
2819 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002820}
2821
2822
Uli Kustererca412e82014-02-01 13:35:05 +01002823bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002824{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002825 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002826 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002827}
2828
2829
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002830bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002831{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002832 PushText( text.Value(), text.CData() );
2833 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002834}
2835
2836
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002837bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002839 PushComment( comment.Value() );
2840 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002841}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002842
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002843bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002845 PushDeclaration( declaration.Value() );
2846 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002847}
2848
2849
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002850bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002851{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002852 PushUnknown( unknown.Value() );
2853 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002854}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002855
Lee Thomason685b8952012-11-12 13:00:06 -08002856} // namespace tinyxml2