blob: 4ff722ba3cd0cae5872f50b6ca667e75bfeec6f7 [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
orbitcowboy710a3322019-05-16 15:30:47 +0200104static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
orbitcowboy710a3322019-05-16 15:30:47 +0200106static const char CARRIAGE_RETURN = static_cast<char>(0x0d); // CR gets filtered out
Lee Thomasonfde6a752012-01-14 18:08:12 -0800107static 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;
orbitcowboy710a3322019-05-16 15:30:47 +0200433 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200438 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200443 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200448 *output = static_cast<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
cugone47e229e2019-04-12 17:27:28 -0500585void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
Lee Thomason51c12712016-06-04 20:18:49 -0700586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
orbitcowboy710a3322019-05-16 15:30:47 +0200588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
cugone47e229e2019-04-12 17:27:28 -0500591void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
592{
593 // horrible syntax trick to make the compiler happy about %llu
594 TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
595}
Lee Thomason51c12712016-06-04 20:18:49 -0700596
Lee Thomason21be8822012-07-15 17:27:22 -0700597bool XMLUtil::ToInt( const char* str, int* value )
598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
606{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
608 return true;
609 }
610 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700611}
612
613bool XMLUtil::ToBool( const char* str, bool* value )
614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 int ival = 0;
616 if ( ToInt( str, &ival )) {
617 *value = (ival==0) ? false : true;
618 return true;
619 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700620 static const char* TRUE[] = { "true", "True", "TRUE", 0 };
621 static const char* FALSE[] = { "false", "False", "FALSE", 0 };
622
623 for (int i = 0; TRUE[i]; ++i) {
624 if (StringEqual(str, TRUE[i])) {
625 *value = true;
626 return true;
627 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700629 for (int i = 0; FALSE[i]; ++i) {
630 if (StringEqual(str, FALSE[i])) {
631 *value = false;
632 return true;
633 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
635 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700636}
637
638
639bool XMLUtil::ToFloat( const char* str, float* value )
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
642 return true;
643 }
644 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700645}
646
Lee Thomason51c12712016-06-04 20:18:49 -0700647
Lee Thomason21be8822012-07-15 17:27:22 -0700648bool XMLUtil::ToDouble( const char* str, double* value )
649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
651 return true;
652 }
653 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700654}
655
656
Lee Thomason51c12712016-06-04 20:18:49 -0700657bool XMLUtil::ToInt64(const char* str, int64_t* value)
658{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700659 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
660 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
orbitcowboy710a3322019-05-16 15:30:47 +0200661 *value = static_cast<int64_t>(v);
Lee Thomason51c12712016-06-04 20:18:49 -0700662 return true;
663 }
664 return false;
665}
666
667
cugone75a5acc2019-04-11 22:03:43 -0500668bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
669 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
670 if(TIXML_SSCANF(str, "%llu", &v) == 1) {
671 *value = (uint64_t)v;
672 return true;
673 }
674 return false;
675}
676
677
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700678char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800679{
Dmitry-Me02384662015-03-03 16:02:13 +0300680 TIXMLASSERT( node );
681 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400682 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000683 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000684 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300685 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300686 *node = 0;
687 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 return p;
689 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Dmitry-Me962083b2015-05-26 11:38:30 +0300691 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 static const char* xmlHeader = { "<?" };
693 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300695 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 static const int xmlHeaderLen = 2;
699 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300701 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
705 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400706 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += xmlHeaderLen;
711 }
712 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p += commentHeaderLen;
716 }
717 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300718 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000720 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 p += cdataHeaderLen;
722 text->SetCData( true );
723 }
724 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300725 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000726 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 p += dtdHeaderLen;
728 }
729 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300730 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000731 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 p += elementHeaderLen;
733 }
734 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300735 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000736 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000738 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740
Dmitry-Me02384662015-03-03 16:02:13 +0300741 TIXMLASSERT( returnNode );
742 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 *node = returnNode;
744 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745}
746
747
Lee Thomason751da522012-02-10 08:50:51 -0800748bool XMLDocument::Accept( XMLVisitor* visitor ) const
749{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300750 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 if ( visitor->VisitEnter( *this ) ) {
752 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
753 if ( !node->Accept( visitor ) ) {
754 break;
755 }
756 }
757 }
758 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800759}
Lee Thomason56bdd022012-02-09 18:16:58 -0800760
761
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800762// --------- XMLNode ----------- //
763
764XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 _document( doc ),
766 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200767 _value(),
kezenatorec694152016-11-26 17:21:43 +1000768 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200770 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700771 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200772 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800773{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800774}
775
776
777XMLNode::~XMLNode()
778{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( _parent ) {
781 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800783}
784
Gumichan010f1fa6d2018-02-01 14:16:24 +0100785const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200786{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300787 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530788 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530789 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200790 return _value.GetStr();
791}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800792
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793void XMLNode::SetValue( const char* str, bool staticMem )
794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 }
798 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800801}
802
Dmitry-Me3f63f212017-06-19 18:25:19 +0300803XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700804{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300805 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700806 if (!clone) return 0;
807
808 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300809 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700810 TIXMLASSERT(childClone);
811 clone->InsertEndChild(childClone);
812 }
813 return clone;
814}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800815
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800816void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800817{
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300819 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300820 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800823}
824
825
826void XMLNode::Unlink( XMLNode* child )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300830 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 if ( child == _firstChild ) {
832 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 if ( child == _lastChild ) {
835 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
Lee Thomasond923c672012-01-23 08:44:25 -0800837
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 if ( child->_prev ) {
839 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 if ( child->_next ) {
842 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
Lee Thomason8a763612017-06-16 09:30:16 -0700844 child->_next = 0;
845 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700846 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800847}
848
849
U-Stream\Leeae25a442012-02-17 17:48:16 -0800850void XMLNode::DeleteChild( XMLNode* node )
851{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300852 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100855 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700856 TIXMLASSERT(node->_prev == 0);
857 TIXMLASSERT(node->_next == 0);
858 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400859 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800860}
861
862
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800863XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
864{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300865 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300866 if ( addThis->_document != _document ) {
867 TIXMLASSERT( false );
868 return 0;
869 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800870 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( _lastChild ) {
873 TIXMLASSERT( _firstChild );
874 TIXMLASSERT( _lastChild->_next == 0 );
875 _lastChild->_next = addThis;
876 addThis->_prev = _lastChild;
877 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 TIXMLASSERT( _firstChild == 0 );
883 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800884
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 addThis->_prev = 0;
886 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800890}
891
892
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
894{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300895 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300896 if ( addThis->_document != _document ) {
897 TIXMLASSERT( false );
898 return 0;
899 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800900 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700901
Lee Thomason624d43f2012-10-12 10:58:48 -0700902 if ( _firstChild ) {
903 TIXMLASSERT( _lastChild );
904 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 _firstChild->_prev = addThis;
907 addThis->_next = _firstChild;
908 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800909
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700913 TIXMLASSERT( _lastChild == 0 );
914 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800915
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 addThis->_prev = 0;
917 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400920 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800921}
922
923
924XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
925{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300926 TIXMLASSERT( addThis );
927 if ( addThis->_document != _document ) {
928 TIXMLASSERT( false );
929 return 0;
930 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700931
Dmitry-Meabb2d042014-12-09 12:59:31 +0300932 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300935 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 return 0;
937 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300938 if ( afterThis == addThis ) {
939 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
940 // Now AddThis must disappear from it's location and then
941 // reappear between BeforeThis and OneAfterAddThis.
942 // So just leave it where it is.
943 return addThis;
944 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800945
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // The last node or the only node.
948 return InsertEndChild( addThis );
949 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800950 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 addThis->_prev = afterThis;
952 addThis->_next = afterThis->_next;
953 afterThis->_next->_prev = addThis;
954 afterThis->_next = addThis;
955 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800957}
958
959
960
961
Dmitry-Me886ad972015-07-22 11:00:51 +0300962const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800963{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300964 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
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 Thomason2c85a712012-01-31 08:24:24 -0800971}
972
973
Dmitry-Me886ad972015-07-22 11:00:51 +0300974const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800975{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300976 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300977 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300979 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 }
982 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800983}
984
985
Dmitry-Me886ad972015-07-22 11:00:51 +0300986const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300988 for( const XMLNode* node = _next; node; node = node->_next ) {
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-Me886ad972015-07-22 11:00:51 +0300998const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999{
Dmitry-Me2667aab2015-04-03 10:56:59 +03001000 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +03001001 const XMLElement* element = node->ToElementWithName( name );
1002 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 }
1006 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001010char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 // This is a recursive method, but thinking about it "at the current level"
1013 // it is a pretty simple flat list:
1014 // <foo/>
1015 // <!-- comment -->
1016 //
1017 // With a special case:
1018 // <foo>
1019 // </foo>
1020 // <!-- comment -->
1021 //
1022 // Where the closing element (/foo) *must* be the next thing after the opening
1023 // element, and the names must match. BUT the tricky bit is that the closing
1024 // element will be read by the child.
1025 //
1026 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1027 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001028
Lee Thomasond946dda2018-04-05 09:11:08 -07001029 XMLDocument::DepthTracker tracker(_document);
1030 if (_document->Error())
1031 return 0;
1032
1033 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001037 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001038 if ( node == 0 ) {
1039 break;
1040 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041
orbitcowboy0e7f2892019-01-15 11:28:49 +01001042 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001043
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001045 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001047 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001049 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 break;
1052 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053
orbitcowboy0e7f2892019-01-15 11:28:49 +01001054 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301055 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001056 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001057 //
1058 // Multiple declarations are allowed but all declarations
1059 // must occur before anything else.
1060 //
1061 // Optimized due to a security test case. If the first node is
1062 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001063 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001064 bool wellLocated = false;
1065
1066 if (ToDocument()) {
1067 if (FirstChild()) {
1068 wellLocated =
1069 FirstChild() &&
1070 FirstChild()->ToDeclaration() &&
1071 LastChild() &&
1072 LastChild()->ToDeclaration();
1073 }
1074 else {
1075 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301076 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001077 }
1078 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001079 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001080 DeleteNode( node );
1081 break;
1082 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301083 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301084
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001085 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001087 // We read the end tag. Return it to the parent.
1088 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001089 if ( parentEndTag ) {
1090 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001091 }
1092 node->_memPool->SetTracked(); // created and then immediately deleted.
1093 DeleteNode( node );
1094 return p;
1095 }
1096
1097 // Handle an end tag returned to this level.
1098 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001099 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001100 if ( endTag.Empty() ) {
1101 if ( ele->ClosingType() == XMLElement::OPEN ) {
1102 mismatch = true;
1103 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001105 else {
1106 if ( ele->ClosingType() != XMLElement::OPEN ) {
1107 mismatch = true;
1108 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001109 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001110 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001113 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001114 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001115 DeleteNode( node );
1116 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001117 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 }
JayXondbfdd8f2014-12-12 20:07:14 -05001119 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001122}
1123
Lee Thomason816d3fa2017-06-05 14:35:55 -07001124/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001125{
1126 if ( node == 0 ) {
1127 return;
1128 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001129 TIXMLASSERT(node->_document);
1130 if (!node->ToDocument()) {
1131 node->_document->MarkInUse(node);
1132 }
1133
Dmitry-Mee3225b12014-09-03 11:03:11 +04001134 MemPool* pool = node->_memPool;
1135 node->~XMLNode();
1136 pool->Free( node );
1137}
1138
Lee Thomason3cebdc42015-01-05 17:16:28 -08001139void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001140{
1141 TIXMLASSERT( insertThis );
1142 TIXMLASSERT( insertThis->_document == _document );
1143
Lee Thomason816d3fa2017-06-05 14:35:55 -07001144 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001145 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001146 }
1147 else {
1148 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001149 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001150 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001151}
1152
Dmitry-Meecb9b072016-10-12 16:44:59 +03001153const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1154{
1155 const XMLElement* element = this->ToElement();
1156 if ( element == 0 ) {
1157 return 0;
1158 }
1159 if ( name == 0 ) {
1160 return element;
1161 }
1162 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1163 return element;
1164 }
1165 return 0;
1166}
1167
Lee Thomason5492a1c2012-01-23 15:32:10 -08001168// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001169char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001172 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001174 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
1176 return p;
1177 }
1178 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1180 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001181 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001183
kezenator4f756162016-11-29 19:46:27 +10001184 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( p && *p ) {
1186 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001187 }
1188 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001189 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 }
1191 }
1192 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001193}
1194
1195
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001196XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 }
1201 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1202 text->SetCData( this->CData() );
1203 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001204}
1205
1206
1207bool XMLText::ShallowEqual( const XMLNode* compare ) const
1208{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001209 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001210 const XMLText* text = compare->ToText();
1211 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212}
1213
1214
Lee Thomason56bdd022012-02-09 18:16:58 -08001215bool XMLText::Accept( XMLVisitor* visitor ) const
1216{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001217 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001219}
1220
1221
Lee Thomason3f57d272012-01-11 15:30:03 -08001222// --------- XMLComment ---------- //
1223
Lee Thomasone4422302012-01-20 17:59:50 -08001224XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001225{
1226}
1227
1228
Lee Thomasonce0763e2012-01-11 15:43:54 -08001229XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001230{
Lee Thomason3f57d272012-01-11 15:30:03 -08001231}
1232
1233
kezenator4f756162016-11-29 19:46:27 +10001234char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001237 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001239 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 }
1241 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001242}
1243
1244
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 }
1250 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1251 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252}
1253
1254
1255bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001258 const XMLComment* comment = compare->ToComment();
1259 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260}
1261
1262
Lee Thomason751da522012-02-10 08:50:51 -08001263bool XMLComment::Accept( XMLVisitor* visitor ) const
1264{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001265 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001267}
Lee Thomason56bdd022012-02-09 18:16:58 -08001268
1269
Lee Thomason50f97b22012-02-11 16:33:40 -08001270// --------- XMLDeclaration ---------- //
1271
1272XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1273{
1274}
1275
1276
1277XMLDeclaration::~XMLDeclaration()
1278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001280}
1281
1282
kezenator4f756162016-11-29 19:46:27 +10001283char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001286 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001288 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 }
1290 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001291}
1292
1293
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001294XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
1299 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1300 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001301}
1302
1303
1304bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1305{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001306 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001307 const XMLDeclaration* declaration = compare->ToDeclaration();
1308 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001309}
1310
1311
1312
Lee Thomason50f97b22012-02-11 16:33:40 -08001313bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1314{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001315 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001317}
1318
1319// --------- XMLUnknown ---------- //
1320
1321XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1322{
1323}
1324
1325
1326XMLUnknown::~XMLUnknown()
1327{
1328}
1329
1330
kezenator4f756162016-11-29 19:46:27 +10001331char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001334 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001336 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 }
1338 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001339}
1340
1341
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001342XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001345 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1348 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001349}
1350
1351
1352bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1353{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001354 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001355 const XMLUnknown* unknown = compare->ToUnknown();
1356 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001357}
1358
1359
Lee Thomason50f97b22012-02-11 16:33:40 -08001360bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1361{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001362 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001364}
1365
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001366// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001367
Gumichan010f1fa6d2018-02-01 14:16:24 +01001368const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001369{
1370 return _name.GetStr();
1371}
1372
Gumichan010f1fa6d2018-02-01 14:16:24 +01001373const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001374{
1375 return _value.GetStr();
1376}
1377
kezenator4f756162016-11-29 19:46:27 +10001378char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001381 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( !p || !*p ) {
1383 return 0;
1384 }
Lee Thomason22aead12012-01-23 13:29:35 -08001385
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001387 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001388 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 return 0;
1390 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001391
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001393 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( *p != '\"' && *p != '\'' ) {
1395 return 0;
1396 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001397
orbitcowboy0e7f2892019-01-15 11:28:49 +01001398 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001400
kezenator4f756162016-11-29 19:46:27 +10001401 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001403}
1404
1405
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001406void XMLAttribute::SetName( const char* n )
1407{
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001409}
1410
1411
Lee Thomason2fa81722012-11-09 12:37:46 -08001412XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001415 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418}
1419
1420
Lee Thomason2fa81722012-11-09 12:37:46 -08001421XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001424 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
1426 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001427}
1428
1429
Lee Thomason51c12712016-06-04 20:18:49 -07001430XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1431{
1432 if (XMLUtil::ToInt64(Value(), value)) {
1433 return XML_SUCCESS;
1434 }
1435 return XML_WRONG_ATTRIBUTE_TYPE;
1436}
1437
1438
cugone75a5acc2019-04-11 22:03:43 -05001439XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1440{
1441 if(XMLUtil::ToUnsigned64(Value(), value)) {
1442 return XML_SUCCESS;
1443 }
1444 return XML_WRONG_ATTRIBUTE_TYPE;
1445}
1446
1447
Lee Thomason2fa81722012-11-09 12:37:46 -08001448XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001451 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001454}
1455
1456
Lee Thomason2fa81722012-11-09 12:37:46 -08001457XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001460 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001463}
1464
1465
Lee Thomason2fa81722012-11-09 12:37:46 -08001466XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001469 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
1471 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001472}
1473
1474
1475void XMLAttribute::SetAttribute( const char* v )
1476{
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001478}
1479
1480
Lee Thomason1ff38e02012-02-14 18:18:16 -08001481void XMLAttribute::SetAttribute( int v )
1482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 char buf[BUF_SIZE];
1484 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001486}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487
1488
1489void XMLAttribute::SetAttribute( unsigned v )
1490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 char buf[BUF_SIZE];
1492 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
1496
Lee Thomason51c12712016-06-04 20:18:49 -07001497void XMLAttribute::SetAttribute(int64_t v)
1498{
1499 char buf[BUF_SIZE];
1500 XMLUtil::ToStr(v, buf, BUF_SIZE);
1501 _value.SetStr(buf);
1502}
1503
Lee Thomasoneffdf952019-08-10 17:49:42 -07001504void XMLAttribute::SetAttribute(uint64_t v)
1505{
1506 char buf[BUF_SIZE];
1507 XMLUtil::ToStr(v, buf, BUF_SIZE);
1508 _value.SetStr(buf);
1509}
Lee Thomason51c12712016-06-04 20:18:49 -07001510
1511
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001512void XMLAttribute::SetAttribute( bool v )
1513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 char buf[BUF_SIZE];
1515 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001517}
1518
1519void XMLAttribute::SetAttribute( double v )
1520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 char buf[BUF_SIZE];
1522 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001524}
1525
1526void XMLAttribute::SetAttribute( float v )
1527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 char buf[BUF_SIZE];
1529 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001531}
1532
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001533
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001534// --------- XMLElement ---------- //
1535XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001536 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001538{
1539}
1540
1541
1542XMLElement::~XMLElement()
1543{
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 while( _rootAttribute ) {
1545 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001546 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001549}
1550
1551
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001552const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1553{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001554 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1556 return a;
1557 }
1558 }
1559 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001560}
1561
1562
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001563const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 const XMLAttribute* a = FindAttribute( name );
1566 if ( !a ) {
1567 return 0;
1568 }
1569 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1570 return a->Value();
1571 }
1572 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001573}
1574
Gumichan010f1fa6d2018-02-01 14:16:24 +01001575int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001576{
1577 int i = defaultValue;
1578 QueryIntAttribute(name, &i);
1579 return i;
1580}
1581
Gumichan010f1fa6d2018-02-01 14:16:24 +01001582unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001583{
1584 unsigned i = defaultValue;
1585 QueryUnsignedAttribute(name, &i);
1586 return i;
1587}
1588
Gumichan010f1fa6d2018-02-01 14:16:24 +01001589int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001590{
1591 int64_t i = defaultValue;
1592 QueryInt64Attribute(name, &i);
1593 return i;
1594}
1595
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01001596uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1597{
1598 uint64_t i = defaultValue;
1599 QueryUnsigned64Attribute(name, &i);
1600 return i;
1601}
1602
Gumichan010f1fa6d2018-02-01 14:16:24 +01001603bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001604{
1605 bool b = defaultValue;
1606 QueryBoolAttribute(name, &b);
1607 return b;
1608}
1609
Gumichan010f1fa6d2018-02-01 14:16:24 +01001610double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001611{
1612 double d = defaultValue;
1613 QueryDoubleAttribute(name, &d);
1614 return d;
1615}
1616
Gumichan010f1fa6d2018-02-01 14:16:24 +01001617float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001618{
1619 float f = defaultValue;
1620 QueryFloatAttribute(name, &f);
1621 return f;
1622}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001623
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001624const char* XMLElement::GetText() const
1625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001627 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 }
1629 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001630}
1631
1632
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001633void XMLElement::SetText( const char* inText )
1634{
Uli Kusterer869bb592014-01-21 01:36:16 +01001635 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001636 FirstChild()->SetValue( inText );
1637 else {
1638 XMLText* theText = GetDocument()->NewText( inText );
1639 InsertFirstChild( theText );
1640 }
1641}
1642
Lee Thomason5bb2d802014-01-24 10:42:57 -08001643
Gumichan010f1fa6d2018-02-01 14:16:24 +01001644void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001645{
1646 char buf[BUF_SIZE];
1647 XMLUtil::ToStr( v, buf, BUF_SIZE );
1648 SetText( buf );
1649}
1650
1651
Gumichan010f1fa6d2018-02-01 14:16:24 +01001652void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001653{
1654 char buf[BUF_SIZE];
1655 XMLUtil::ToStr( v, buf, BUF_SIZE );
1656 SetText( buf );
1657}
1658
1659
Lee Thomason51c12712016-06-04 20:18:49 -07001660void XMLElement::SetText(int64_t v)
1661{
1662 char buf[BUF_SIZE];
1663 XMLUtil::ToStr(v, buf, BUF_SIZE);
1664 SetText(buf);
1665}
1666
cugone47e229e2019-04-12 17:27:28 -05001667void XMLElement::SetText(uint64_t v) {
1668 char buf[BUF_SIZE];
1669 XMLUtil::ToStr(v, buf, BUF_SIZE);
1670 SetText(buf);
1671}
1672
Lee Thomason51c12712016-06-04 20:18:49 -07001673
1674void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001675{
1676 char buf[BUF_SIZE];
1677 XMLUtil::ToStr( v, buf, BUF_SIZE );
1678 SetText( buf );
1679}
1680
1681
Gumichan010f1fa6d2018-02-01 14:16:24 +01001682void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001683{
1684 char buf[BUF_SIZE];
1685 XMLUtil::ToStr( v, buf, BUF_SIZE );
1686 SetText( buf );
1687}
1688
1689
Gumichan010f1fa6d2018-02-01 14:16:24 +01001690void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001691{
1692 char buf[BUF_SIZE];
1693 XMLUtil::ToStr( v, buf, BUF_SIZE );
1694 SetText( buf );
1695}
1696
1697
MortenMacFly4ee49f12013-01-14 20:03:14 +01001698XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001699{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001701 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001702 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 return XML_SUCCESS;
1704 }
1705 return XML_CAN_NOT_CONVERT_TEXT;
1706 }
1707 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001708}
1709
1710
MortenMacFly4ee49f12013-01-14 20:03:14 +01001711XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001714 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001715 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 return XML_SUCCESS;
1717 }
1718 return XML_CAN_NOT_CONVERT_TEXT;
1719 }
1720 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001721}
1722
1723
Lee Thomason51c12712016-06-04 20:18:49 -07001724XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1725{
1726 if (FirstChild() && FirstChild()->ToText()) {
1727 const char* t = FirstChild()->Value();
1728 if (XMLUtil::ToInt64(t, ival)) {
1729 return XML_SUCCESS;
1730 }
1731 return XML_CAN_NOT_CONVERT_TEXT;
1732 }
1733 return XML_NO_TEXT_NODE;
1734}
1735
1736
cugone1dbfe312019-04-12 17:33:49 -05001737XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const
1738{
cugone47e229e2019-04-12 17:27:28 -05001739 if(FirstChild() && FirstChild()->ToText()) {
1740 const char* t = FirstChild()->Value();
1741 if(XMLUtil::ToUnsigned64(t, ival)) {
1742 return XML_SUCCESS;
1743 }
1744 return XML_CAN_NOT_CONVERT_TEXT;
1745 }
1746 return XML_NO_TEXT_NODE;
1747}
1748
1749
MortenMacFly4ee49f12013-01-14 20:03:14 +01001750XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001753 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001754 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 return XML_SUCCESS;
1756 }
1757 return XML_CAN_NOT_CONVERT_TEXT;
1758 }
1759 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001760}
1761
1762
MortenMacFly4ee49f12013-01-14 20:03:14 +01001763XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001764{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001766 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001767 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 return XML_SUCCESS;
1769 }
1770 return XML_CAN_NOT_CONVERT_TEXT;
1771 }
1772 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001773}
1774
1775
MortenMacFly4ee49f12013-01-14 20:03:14 +01001776XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001777{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001779 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001780 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 return XML_SUCCESS;
1782 }
1783 return XML_CAN_NOT_CONVERT_TEXT;
1784 }
1785 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001786}
1787
Josh Wittnercf3dd092016-10-11 18:57:17 -07001788int XMLElement::IntText(int defaultValue) const
1789{
1790 int i = defaultValue;
1791 QueryIntText(&i);
1792 return i;
1793}
1794
1795unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1796{
1797 unsigned i = defaultValue;
1798 QueryUnsignedText(&i);
1799 return i;
1800}
1801
1802int64_t XMLElement::Int64Text(int64_t defaultValue) const
1803{
1804 int64_t i = defaultValue;
1805 QueryInt64Text(&i);
1806 return i;
1807}
1808
cugone1dbfe312019-04-12 17:33:49 -05001809uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1810{
1811 uint64_t i = defaultValue;
1812 QueryUnsigned64Text(&i);
1813 return i;
1814}
1815
Josh Wittnercf3dd092016-10-11 18:57:17 -07001816bool XMLElement::BoolText(bool defaultValue) const
1817{
1818 bool b = defaultValue;
1819 QueryBoolText(&b);
1820 return b;
1821}
1822
1823double XMLElement::DoubleText(double defaultValue) const
1824{
1825 double d = defaultValue;
1826 QueryDoubleText(&d);
1827 return d;
1828}
1829
1830float XMLElement::FloatText(float defaultValue) const
1831{
1832 float f = defaultValue;
1833 QueryFloatText(&f);
1834 return f;
1835}
Lee Thomason21be8822012-07-15 17:27:22 -07001836
1837
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001838XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1839{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 XMLAttribute* last = 0;
1841 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1846 break;
1847 }
1848 }
1849 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001850 attrib = CreateAttribute();
1851 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001853 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 }
1856 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001857 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
1860 attrib->SetName( name );
1861 }
1862 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001863}
1864
1865
U-Stream\Leeae25a442012-02-17 17:48:16 -08001866void XMLElement::DeleteAttribute( const char* name )
1867{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1871 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
1874 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001877 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 break;
1879 }
1880 prev = a;
1881 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001882}
1883
1884
kezenator4f756162016-11-29 19:46:27 +10001885char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001886{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001888
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 // Read the attributes.
1890 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001892 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001893 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 return 0;
1895 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001896
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001898 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001899 XMLAttribute* attrib = CreateAttribute();
1900 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001901 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001902
orbitcowboy0e7f2892019-01-15 11:28:49 +01001903 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001904
kezenator4f756162016-11-29 19:46:27 +10001905 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001907 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001908 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return 0;
1910 }
1911 // There is a minor bug here: if the attribute in the source xml
1912 // document is duplicated, it will not be detected and the
1913 // attribute will be doubly added. However, tracking the 'prevAttribute'
1914 // avoids re-scanning the attribute list. Preferring performance for
1915 // now, may reconsider in the future.
1916 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001917 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
1920 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001921 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 prevAttribute = attrib;
1925 }
1926 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 else if ( *p == '>' ) {
1928 ++p;
1929 break;
1930 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001931 // end of the tag
1932 else if ( *p == '/' && *(p+1) == '>' ) {
1933 _closingType = CLOSED;
1934 return p+2; // done; sealed element.
1935 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001937 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 return 0;
1939 }
1940 }
1941 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001942}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001943
Dmitry-Mee3225b12014-09-03 11:03:11 +04001944void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1945{
1946 if ( attribute == 0 ) {
1947 return;
1948 }
1949 MemPool* pool = attribute->_memPool;
1950 attribute->~XMLAttribute();
1951 pool->Free( attribute );
1952}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001953
Dmitry-Mea60caa22016-11-22 18:28:08 +03001954XMLAttribute* XMLElement::CreateAttribute()
1955{
1956 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1957 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001958 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001959 attrib->_memPool = &_document->_attributePool;
1960 attrib->_memPool->SetTracked();
1961 return attrib;
1962}
1963
ngc92e6202452019-12-03 16:25:53 +01001964
1965XMLElement* XMLElement::PushNewChildElement(const char* name)
1966{
1967 XMLElement* element = _document->NewElement(name);
1968 // by construction, the new element has the same Document, so this
1969 // call will always succeed
1970 InsertEndChild(element);
1971 return element;
1972}
1973
1974XMLComment* XMLElement::PushNewChildComment(const char* comment)
1975{
1976 XMLComment* element = _document->NewComment(comment);
1977 InsertEndChild(element);
1978 return element;
1979}
1980
1981XMLText* XMLElement::PushNewChildText(const char* text)
1982{
1983 XMLText* element = _document->NewText(text);
1984 InsertEndChild(element);
1985 return element;
1986}
1987
1988XMLDeclaration* XMLElement::PushNewChildDeclaration(const char* text)
1989{
1990 XMLDeclaration* element = _document->NewDeclaration(text);
1991 InsertEndChild(element);
1992 return element;
1993}
1994
1995XMLUnknown* XMLElement::PushNewUnknown(const char* text)
1996{
1997 XMLUnknown* element = _document->NewUnknown(text);
1998 InsertEndChild(element);
1999 return element;
2000}
2001
2002
2003
Lee Thomason67d61312012-01-24 16:01:51 -08002004//
2005// <ele></ele>
2006// <ele>foo<b>bar</b></ele>
2007//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002008char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08002009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10002011 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08002012
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 // The closing element is the </element> form. It is
2014 // parsed just like a regular element then deleted from
2015 // the DOM.
2016 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 ++p;
2019 }
Lee Thomason67d61312012-01-24 16:01:51 -08002020
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 p = _value.ParseName( p );
2022 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 return 0;
2024 }
Lee Thomason67d61312012-01-24 16:01:51 -08002025
kezenator4f756162016-11-29 19:46:27 +10002026 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03002027 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 return p;
2029 }
Lee Thomason67d61312012-01-24 16:01:51 -08002030
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002031 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08002033}
2034
2035
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002036
2037XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
2042 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
2043 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2044 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
2045 }
2046 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002047}
2048
2049
2050bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2051{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002052 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03002054 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002055
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 const XMLAttribute* a=FirstAttribute();
2057 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002058
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 while ( a && b ) {
2060 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2061 return false;
2062 }
2063 a = a->Next();
2064 b = b->Next();
2065 }
2066 if ( a || b ) {
2067 // different count
2068 return false;
2069 }
2070 return true;
2071 }
2072 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002073}
2074
2075
Lee Thomason751da522012-02-10 08:50:51 -08002076bool XMLElement::Accept( XMLVisitor* visitor ) const
2077{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002078 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2081 if ( !node->Accept( visitor ) ) {
2082 break;
2083 }
2084 }
2085 }
2086 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08002087}
Lee Thomason56bdd022012-02-09 18:16:58 -08002088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002089
Lee Thomason3f57d272012-01-11 15:30:03 -08002090// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002091
2092// Warning: List must match 'enum XMLError'
2093const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2094 "XML_SUCCESS",
2095 "XML_NO_ATTRIBUTE",
2096 "XML_WRONG_ATTRIBUTE_TYPE",
2097 "XML_ERROR_FILE_NOT_FOUND",
2098 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2099 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002100 "XML_ERROR_PARSING_ELEMENT",
2101 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002102 "XML_ERROR_PARSING_TEXT",
2103 "XML_ERROR_PARSING_CDATA",
2104 "XML_ERROR_PARSING_COMMENT",
2105 "XML_ERROR_PARSING_DECLARATION",
2106 "XML_ERROR_PARSING_UNKNOWN",
2107 "XML_ERROR_EMPTY_DOCUMENT",
2108 "XML_ERROR_MISMATCHED_ELEMENT",
2109 "XML_ERROR_PARSING",
2110 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002111 "XML_NO_TEXT_NODE",
2112 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002113};
2114
2115
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002116XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 _writeBOM( false ),
2119 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002120 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002121 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002122 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002123 _errorLineNum( 0 ),
2124 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002125 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002126 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002127 _unlinked(),
2128 _elementPool(),
2129 _attributePool(),
2130 _textPool(),
2131 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002132{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002133 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2134 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002135}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002136
2137
Lee Thomason3f57d272012-01-11 15:30:03 -08002138XMLDocument::~XMLDocument()
2139{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002140 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002141}
2142
2143
Lee Thomason816d3fa2017-06-05 14:35:55 -07002144void XMLDocument::MarkInUse(XMLNode* node)
2145{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002146 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002147 TIXMLASSERT(node->_parent == 0);
2148
2149 for (int i = 0; i < _unlinked.Size(); ++i) {
2150 if (node == _unlinked[i]) {
2151 _unlinked.SwapRemove(i);
2152 break;
2153 }
2154 }
2155}
2156
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002157void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002158{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002159 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002160 while( _unlinked.Size()) {
2161 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2162 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002163
Peter Matula50689912018-01-09 12:52:26 +01002164#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002165 const bool hadError = Error();
2166#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002167 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002168
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 delete [] _charBuffer;
2170 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002171 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002172
2173#if 0
2174 _textPool.Trace( "text" );
2175 _elementPool.Trace( "element" );
2176 _commentPool.Trace( "comment" );
2177 _attributePool.Trace( "attribute" );
2178#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002179
Peter Matula50689912018-01-09 12:52:26 +01002180#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002181 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002182 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2183 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2184 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2185 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2186 }
2187#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002188}
2189
Lee Thomason3f57d272012-01-11 15:30:03 -08002190
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002191void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002192{
2193 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002194 if (target == this) {
2195 return; // technically success - a no-op.
2196 }
Lee Thomason7085f002017-06-01 18:09:43 -07002197
2198 target->Clear();
2199 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2200 target->InsertEndChild(node->DeepClone(target));
2201 }
2202}
2203
Lee Thomason2c85a712012-01-31 08:24:24 -08002204XMLElement* XMLDocument::NewElement( const char* name )
2205{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002206 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 ele->SetName( name );
2208 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002209}
2210
2211
Lee Thomason1ff38e02012-02-14 18:18:16 -08002212XMLComment* XMLDocument::NewComment( const char* str )
2213{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002214 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 comment->SetValue( str );
2216 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002217}
2218
2219
2220XMLText* XMLDocument::NewText( const char* str )
2221{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002222 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 text->SetValue( str );
2224 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002225}
2226
2227
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002228XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2229{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002230 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2232 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002233}
2234
2235
2236XMLUnknown* XMLDocument::NewUnknown( const char* str )
2237{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002238 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 unk->SetValue( str );
2240 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002241}
2242
Dmitry-Me01578db2014-08-19 10:18:48 +04002243static FILE* callfopen( const char* filepath, const char* mode )
2244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002245 TIXMLASSERT( filepath );
2246 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002247#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2248 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002249 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002250 if ( err ) {
2251 return 0;
2252 }
2253#else
2254 FILE* fp = fopen( filepath, mode );
2255#endif
2256 return fp;
2257}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002258
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002259void XMLDocument::DeleteNode( XMLNode* node ) {
2260 TIXMLASSERT( node );
2261 TIXMLASSERT(node->_document == this );
2262 if (node->_parent) {
2263 node->_parent->DeleteChild( node );
2264 }
2265 else {
2266 // Isn't in the tree.
2267 // Use the parent delete.
2268 // Also, we need to mark it tracked: we 'know'
2269 // it was never used.
2270 node->_memPool->SetTracked();
2271 // Call the static XMLNode version:
2272 XMLNode::DeleteNode(node);
2273 }
2274}
2275
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002276
Lee Thomason2fa81722012-11-09 12:37:46 -08002277XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002278{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002279 if ( !filename ) {
2280 TIXMLASSERT( false );
2281 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2282 return _errorID;
2283 }
2284
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002285 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002286 FILE* fp = callfopen( filename, "rb" );
2287 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002288 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 }
2291 LoadFile( fp );
2292 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002293 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294}
2295
Dmitry-Me901fed52015-09-25 10:29:51 +03002296// This is likely overengineered template art to have a check that unsigned long value incremented
2297// by one still fits into size_t. If size_t type is larger than unsigned long type
2298// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2299// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2300// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2301// types sizes relate to each other.
2302template
2303<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2304struct LongFitsIntoSizeTMinusOne {
2305 static bool Fits( unsigned long value )
2306 {
orbitcowboy710a3322019-05-16 15:30:47 +02002307 return value < static_cast<size_t>(-1);
Dmitry-Me901fed52015-09-25 10:29:51 +03002308 }
2309};
2310
2311template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002312struct LongFitsIntoSizeTMinusOne<false> {
2313 static bool Fits( unsigned long )
2314 {
2315 return true;
2316 }
2317};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002318
Lee Thomason2fa81722012-11-09 12:37:46 -08002319XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002320{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002321 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002323 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002324 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002325 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002326 return _errorID;
2327 }
2328
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002330 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002332 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002333 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002334 return _errorID;
2335 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002336 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002337
Dmitry-Me901fed52015-09-25 10:29:51 +03002338 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002339 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002340 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002341 return _errorID;
2342 }
2343
Dmitry-Me72801b82015-05-07 09:41:39 +03002344 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002345 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002346 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002348
Dmitry-Me72801b82015-05-07 09:41:39 +03002349 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002350 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002352 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002354 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002355 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002357
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002359
Dmitry-Me97476b72015-01-01 16:15:57 +03002360 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002362}
2363
2364
Lee Thomason2fa81722012-11-09 12:37:46 -08002365XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002366{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002367 if ( !filename ) {
2368 TIXMLASSERT( false );
2369 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2370 return _errorID;
2371 }
2372
Dmitry-Me01578db2014-08-19 10:18:48 +04002373 FILE* fp = callfopen( filename, "w" );
2374 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002375 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 }
2378 SaveFile(fp, compact);
2379 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002381}
2382
2383
Lee Thomason2fa81722012-11-09 12:37:46 -08002384XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002385{
Ant Mitchell189198f2015-03-24 16:20:36 +00002386 // Clear any error from the last save, otherwise it will get reported
2387 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002388 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 XMLPrinter stream( fp, compact );
2390 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002391 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002392}
2393
Lee Thomason1ff38e02012-02-14 18:18:16 -08002394
Lee Thomason2fa81722012-11-09 12:37:46 -08002395XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002396{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002397 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002398
Lee Thomason82d32002014-02-21 22:47:18 -08002399 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002400 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002402 }
orbitcowboy710a3322019-05-16 15:30:47 +02002403 if ( len == static_cast<size_t>(-1) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 len = strlen( p );
2405 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002406 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002407 _charBuffer = new char[ len+1 ];
2408 memcpy( _charBuffer, p, len );
2409 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002410
Dmitry-Me97476b72015-01-01 16:15:57 +03002411 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002412 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002413 // clean up now essentially dangling memory.
2414 // and the parse fail can put objects in the
2415 // pools that are dead and inaccessible.
2416 DeleteChildren();
2417 _elementPool.Clear();
2418 _attributePool.Clear();
2419 _textPool.Clear();
2420 _commentPool.Clear();
2421 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002422 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002423}
2424
2425
PKEuS1c5f99e2013-07-06 11:28:39 +02002426void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002427{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002428 if ( streamer ) {
2429 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002431 else {
2432 XMLPrinter stdoutStreamer( stdout );
2433 Accept( &stdoutStreamer );
2434 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002435}
2436
2437
Lee Thomasonaa188392017-09-19 17:54:31 -07002438void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002439{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002440 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002442 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002443 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002444
orbitcowboy0e7f2892019-01-15 11:28:49 +01002445 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002446 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002447
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002448 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002449 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 -07002450
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002451 if (format) {
2452 size_t len = strlen(buffer);
2453 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2454 len = strlen(buffer);
2455
2456 va_list va;
2457 va_start(va, format);
2458 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2459 va_end(va);
2460 }
2461 _errorStr.SetStr(buffer);
2462 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002463}
2464
Lee Thomasonaa188392017-09-19 17:54:31 -07002465
Lee Thomasone90e9012016-12-24 07:34:39 -08002466/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002467{
kezenator5a700712016-11-26 13:54:42 +10002468 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2469 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002470 TIXMLASSERT( errorName && errorName[0] );
2471 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002472}
Lee Thomason5cae8972012-01-24 18:03:07 -08002473
Gumichan010f1fa6d2018-02-01 14:16:24 +01002474const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002475{
Lee Thomasonaa188392017-09-19 17:54:31 -07002476 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002477}
2478
Lee Thomasonf49b9652017-10-11 10:57:49 -07002479
2480void XMLDocument::PrintError() const
2481{
2482 printf("%s\n", ErrorStr());
2483}
2484
kezenator5a700712016-11-26 13:54:42 +10002485const char* XMLDocument::ErrorName() const
2486{
Lee Thomasone90e9012016-12-24 07:34:39 -08002487 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002488}
2489
Dmitry-Me97476b72015-01-01 16:15:57 +03002490void XMLDocument::Parse()
2491{
2492 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2493 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002494 _parseCurLineNum = 1;
2495 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002496 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002497 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002498 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002499 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002500 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002501 return;
2502 }
kezenator4f756162016-11-29 19:46:27 +10002503 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002504}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002505
Lee Thomasonf928c352018-04-05 09:24:20 -07002506void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002507{
2508 _parsingDepth++;
2509 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002510 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002511 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002512}
2513
Lee Thomasonf928c352018-04-05 09:24:20 -07002514void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002515{
2516 TIXMLASSERT(_parsingDepth > 0);
2517 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002518}
2519
PKEuS1bfb9542013-08-04 13:51:17 +02002520XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002521 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002522 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002523 _firstElement( true ),
2524 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002525 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002526 _textDepth( -1 ),
2527 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002528 _compactMode( compact ),
2529 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002532 _entityFlag[i] = false;
2533 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 }
2535 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002536 const char entityValue = entities[i].value;
orbitcowboy710a3322019-05-16 15:30:47 +02002537 const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
Dmitry-Mea28eb072017-08-25 18:34:18 +03002538 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2539 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002540 }
orbitcowboy710a3322019-05-16 15:30:47 +02002541 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2542 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2543 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002544 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002545}
2546
2547
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002548void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002549{
2550 va_list va;
2551 va_start( va, format );
2552
Lee Thomason624d43f2012-10-12 10:58:48 -07002553 if ( _fp ) {
2554 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002555 }
2556 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002557 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 // Close out and re-start the va-args
2559 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002560 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002562 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002563 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002564 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002565 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002566 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002567}
2568
2569
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002570void XMLPrinter::Write( const char* data, size_t size )
2571{
2572 if ( _fp ) {
2573 fwrite ( data , sizeof(char), size, _fp);
2574 }
2575 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002576 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002577 memcpy( p, data, size );
2578 p[size] = 0;
2579 }
2580}
2581
2582
2583void XMLPrinter::Putc( char ch )
2584{
2585 if ( _fp ) {
2586 fputc ( ch, _fp);
2587 }
2588 else {
2589 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2590 p[0] = ch;
2591 p[1] = 0;
2592 }
2593}
2594
2595
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002596void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002597{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002598 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002599 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002600 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002601}
2602
2603
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002604void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002606 // Look for runs of bytes between entities to print.
2607 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002608
Lee Thomason624d43f2012-10-12 10:58:48 -07002609 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002610 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002612 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 // Remember, char is sometimes signed. (How many times has that bitten me?)
2614 if ( *q > 0 && *q < ENTITY_RANGE ) {
2615 // Check for entities. If one is found, flush
2616 // the stream up until the entity, write the
2617 // entity, and keep looking.
orbitcowboy710a3322019-05-16 15:30:47 +02002618 if ( flag[static_cast<unsigned char>(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002620 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002621 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002622 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002623 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002624 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002625 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002626 for( int i=0; i<NUM_ENTITIES; ++i ) {
2627 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002628 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002629 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002630 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002631 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 break;
2633 }
2634 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002635 if ( !entityPatternPrinted ) {
2636 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2637 TIXMLASSERT( false );
2638 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002639 ++p;
2640 }
2641 }
2642 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002643 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 }
Derek Quambe69ae62018-04-18 13:40:46 -05002645 // Flush the remaining string. This will be the entire
2646 // string if an entity wasn't found.
2647 if ( p < q ) {
2648 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002649 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Derek Quambe69ae62018-04-18 13:40:46 -05002650 Write( p, toPrint );
2651 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 }
Derek Quambe69ae62018-04-18 13:40:46 -05002653 else {
2654 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002655 }
Lee Thomason857b8682012-01-25 17:50:25 -08002656}
2657
U-Stream\Leeae25a442012-02-17 17:48:16 -08002658
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002659void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002660{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002661 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002662 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 +03002663 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 }
2665 if ( writeDec ) {
2666 PushDeclaration( "xml version=\"1.0\"" );
2667 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002668}
2669
2670
Uli Kusterer593a33d2014-02-01 12:48:51 +01002671void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002672{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002673 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002674 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002675
Uli Kusterer593a33d2014-02-01 12:48:51 +01002676 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002677 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002678 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002679 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002680 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002681 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002682
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002683 Write ( "<" );
2684 Write ( name );
2685
Lee Thomason624d43f2012-10-12 10:58:48 -07002686 _elementJustOpened = true;
2687 _firstElement = false;
2688 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002689}
2690
2691
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002692void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002693{
Lee Thomason624d43f2012-10-12 10:58:48 -07002694 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002695 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002696 Write( name );
2697 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002698 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002699 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002700}
2701
2702
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002703void XMLPrinter::PushAttribute( const char* name, int v )
2704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002705 char buf[BUF_SIZE];
2706 XMLUtil::ToStr( v, buf, BUF_SIZE );
2707 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002708}
2709
2710
2711void XMLPrinter::PushAttribute( const char* name, unsigned v )
2712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002713 char buf[BUF_SIZE];
2714 XMLUtil::ToStr( v, buf, BUF_SIZE );
2715 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002716}
2717
2718
Lee Thomason51c12712016-06-04 20:18:49 -07002719void XMLPrinter::PushAttribute(const char* name, int64_t v)
2720{
2721 char buf[BUF_SIZE];
2722 XMLUtil::ToStr(v, buf, BUF_SIZE);
2723 PushAttribute(name, buf);
2724}
2725
2726
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002727void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2728{
2729 char buf[BUF_SIZE];
2730 XMLUtil::ToStr(v, buf, BUF_SIZE);
2731 PushAttribute(name, buf);
2732}
2733
2734
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002735void XMLPrinter::PushAttribute( const char* name, bool v )
2736{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002737 char buf[BUF_SIZE];
2738 XMLUtil::ToStr( v, buf, BUF_SIZE );
2739 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002740}
2741
2742
2743void XMLPrinter::PushAttribute( const char* name, double v )
2744{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002745 char buf[BUF_SIZE];
2746 XMLUtil::ToStr( v, buf, BUF_SIZE );
2747 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002748}
2749
2750
Uli Kustererca412e82014-02-01 13:35:05 +01002751void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002752{
Lee Thomason624d43f2012-10-12 10:58:48 -07002753 --_depth;
2754 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002755
Lee Thomason624d43f2012-10-12 10:58:48 -07002756 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002757 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002758 }
2759 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002760 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002761 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002762 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002763 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002764 Write ( "</" );
2765 Write ( name );
2766 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002767 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002768
Lee Thomason624d43f2012-10-12 10:58:48 -07002769 if ( _textDepth == _depth ) {
2770 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002771 }
Uli Kustererca412e82014-02-01 13:35:05 +01002772 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002773 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002774 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002775 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002776}
2777
2778
Dmitry-Mea092bc12014-12-23 17:57:05 +03002779void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002780{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002781 if ( !_elementJustOpened ) {
2782 return;
2783 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002784 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002785 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002786}
2787
2788
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002789void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002790{
Lee Thomason624d43f2012-10-12 10:58:48 -07002791 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002792
Dmitry-Mea092bc12014-12-23 17:57:05 +03002793 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002794 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002795 Write( "<![CDATA[" );
2796 Write( text );
2797 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002798 }
2799 else {
2800 PrintString( text, true );
2801 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002802}
2803
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002804
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002805void XMLPrinter::PushText( int64_t value )
2806{
2807 char buf[BUF_SIZE];
2808 XMLUtil::ToStr( value, buf, BUF_SIZE );
2809 PushText( buf, false );
2810}
2811
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002812
2813void XMLPrinter::PushText( uint64_t value )
2814{
2815 char buf[BUF_SIZE];
2816 XMLUtil::ToStr(value, buf, BUF_SIZE);
2817 PushText(buf, false);
2818}
2819
2820
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002821void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002822{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002823 char buf[BUF_SIZE];
2824 XMLUtil::ToStr( value, buf, BUF_SIZE );
2825 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002826}
2827
2828
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002829void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002830{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002831 char buf[BUF_SIZE];
2832 XMLUtil::ToStr( value, buf, BUF_SIZE );
2833 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002834}
2835
2836
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002837void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002839 char buf[BUF_SIZE];
2840 XMLUtil::ToStr( value, buf, BUF_SIZE );
2841 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002842}
2843
2844
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002845void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002846{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002847 char buf[BUF_SIZE];
2848 XMLUtil::ToStr( value, buf, BUF_SIZE );
2849 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002850}
2851
2852
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002853void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002854{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002855 char buf[BUF_SIZE];
2856 XMLUtil::ToStr( value, buf, BUF_SIZE );
2857 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002858}
2859
Lee Thomason5cae8972012-01-24 18:03:07 -08002860
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002861void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002862{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002863 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002864 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002865 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002866 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002867 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002868 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002869
2870 Write( "<!--" );
2871 Write( comment );
2872 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002873}
Lee Thomason751da522012-02-10 08:50:51 -08002874
2875
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002876void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002877{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002878 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002879 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002880 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002881 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002882 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002883 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002884
2885 Write( "<?" );
2886 Write( value );
2887 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002888}
2889
2890
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002891void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002892{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002893 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002894 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002895 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002896 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002897 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002898 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002899
2900 Write( "<!" );
2901 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002902 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002903}
2904
2905
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002906bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002907{
Lee Thomason624d43f2012-10-12 10:58:48 -07002908 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002909 if ( doc.HasBOM() ) {
2910 PushHeader( true, false );
2911 }
2912 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002913}
2914
2915
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002916bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002917{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002918 const XMLElement* parentElem = 0;
2919 if ( element.Parent() ) {
2920 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002921 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002922 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002923 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002924 while ( attribute ) {
2925 PushAttribute( attribute->Name(), attribute->Value() );
2926 attribute = attribute->Next();
2927 }
2928 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002929}
2930
2931
Uli Kustererca412e82014-02-01 13:35:05 +01002932bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002933{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002934 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002935 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002936}
2937
2938
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002939bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002941 PushText( text.Value(), text.CData() );
2942 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002943}
2944
2945
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002946bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002948 PushComment( comment.Value() );
2949 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002950}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002951
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002952bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002954 PushDeclaration( declaration.Value() );
2955 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002956}
2957
2958
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002959bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002960{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002961 PushUnknown( unknown.Value() );
2962 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002963}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002964
Lee Thomason685b8952012-11-12 13:00:06 -08002965} // namespace tinyxml2