blob: 2622dd374e0908f68cd85a000d52ea8efb4891ef [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
orbitcowboy0e7f2892019-01-15 11:28:49 +010048 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070049 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
orbitcowboy0e7f2892019-01-15 11:28:49 +010055 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070056 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100200 const char endChar = *endTag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 // Inner loop of text parsing.
204 while ( *p ) {
205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
206 Set( start, p, strFlags );
207 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000208 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000209 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 }
211 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300212 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 }
214 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215}
216
217
218char* StrPair::ParseName( char* p )
219{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 return 0;
222 }
JayXonee525db2014-12-24 04:01:42 -0500223 if ( !XMLUtil::IsNameStartChar( *p ) ) {
224 return 0;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400227 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500228 ++p;
229 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 ++p;
231 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800232
JayXonee525db2014-12-24 04:01:42 -0500233 Set( start, p, 0 );
234 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235}
236
237
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238void StrPair::CollapseWhitespace()
239{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400240 // Adjusting _start would cause undefined behavior on delete[]
241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300245 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300246 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700248
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700249 while( *p ) {
250 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800251 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 if ( *p == 0 ) {
253 break; // don't write to q; this trims the trailing space.
254 }
255 *q = ' ';
256 ++q;
257 }
258 *q = *p;
259 ++q;
260 ++p;
261 }
262 *q = 0;
263 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700264}
265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267const char* StrPair::GetStr()
268{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300269 TIXMLASSERT( _start );
270 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags & NEEDS_FLUSH ) {
272 *_end = 0;
273 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300276 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700277 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800278
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 while( p < _end ) {
280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 // CR-LF pair becomes LF
282 // CR alone becomes LF
283 // LF-CR becomes LF
284 if ( *(p+1) == LF ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300290 *q = LF;
291 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 if ( *(p+1) == CR ) {
295 p += 2;
296 }
297 else {
298 ++p;
299 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300300 *q = LF;
301 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 // Entities handled by tinyXML2:
305 // - special entities in the entity table [in/out]
306 // - numeric character reference [in]
307 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400310 const int buflen = 10;
311 char buf[buflen] = { 0 };
312 int len = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100313 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me6f51c802015-03-14 13:25:03 +0300314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
448 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
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
588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (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 }
620 if ( StringEqual( str, "true" ) ) {
621 *value = true;
622 return true;
623 }
624 else if ( StringEqual( str, "false" ) ) {
625 *value = false;
626 return true;
627 }
628 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700629}
630
631
632bool XMLUtil::ToFloat( const char* str, float* value )
633{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
635 return true;
636 }
637 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700638}
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640
Lee Thomason21be8822012-07-15 17:27:22 -0700641bool XMLUtil::ToDouble( const char* str, double* value )
642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
644 return true;
645 }
646 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700647}
648
649
Lee Thomason51c12712016-06-04 20:18:49 -0700650bool XMLUtil::ToInt64(const char* str, int64_t* value)
651{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700652 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
653 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
654 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700655 return true;
656 }
657 return false;
658}
659
660
cugone75a5acc2019-04-11 22:03:43 -0500661bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
662 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
663 if(TIXML_SSCANF(str, "%llu", &v) == 1) {
664 *value = (uint64_t)v;
665 return true;
666 }
667 return false;
668}
669
670
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700671char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800672{
Dmitry-Me02384662015-03-03 16:02:13 +0300673 TIXMLASSERT( node );
674 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400675 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000676 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000677 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300678 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300679 *node = 0;
680 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 return p;
682 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800683
Dmitry-Me962083b2015-05-26 11:38:30 +0300684 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 static const char* xmlHeader = { "<?" };
686 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300688 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 static const int xmlHeaderLen = 2;
692 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300694 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800696
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
698 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400699 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300701 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000702 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 p += xmlHeaderLen;
704 }
705 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300706 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000707 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 p += commentHeaderLen;
709 }
710 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300711 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000713 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 p += cdataHeaderLen;
715 text->SetCData( true );
716 }
717 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300718 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000719 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 p += dtdHeaderLen;
721 }
722 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300723 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000724 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 p += elementHeaderLen;
726 }
727 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300728 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000729 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000731 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733
Dmitry-Me02384662015-03-03 16:02:13 +0300734 TIXMLASSERT( returnNode );
735 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 *node = returnNode;
737 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800738}
739
740
Lee Thomason751da522012-02-10 08:50:51 -0800741bool XMLDocument::Accept( XMLVisitor* visitor ) const
742{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300743 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 if ( visitor->VisitEnter( *this ) ) {
745 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
746 if ( !node->Accept( visitor ) ) {
747 break;
748 }
749 }
750 }
751 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800752}
Lee Thomason56bdd022012-02-09 18:16:58 -0800753
754
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800755// --------- XMLNode ----------- //
756
757XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 _document( doc ),
759 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200760 _value(),
kezenatorec694152016-11-26 17:21:43 +1000761 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200763 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700764 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200765 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800766{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800767}
768
769
770XMLNode::~XMLNode()
771{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 if ( _parent ) {
774 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800776}
777
Gumichan010f1fa6d2018-02-01 14:16:24 +0100778const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200779{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300780 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530781 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530782 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200783 return _value.GetStr();
784}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800785
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800786void XMLNode::SetValue( const char* str, bool staticMem )
787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
791 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700792 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800794}
795
Dmitry-Me3f63f212017-06-19 18:25:19 +0300796XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700797{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300798 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700799 if (!clone) return 0;
800
801 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300802 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700803 TIXMLASSERT(childClone);
804 clone->InsertEndChild(childClone);
805 }
806 return clone;
807}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800808
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800809void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800810{
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300812 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300813 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800816}
817
818
819void XMLNode::Unlink( XMLNode* child )
820{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300821 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300822 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300823 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 if ( child == _firstChild ) {
825 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 if ( child == _lastChild ) {
828 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomasond923c672012-01-23 08:44:25 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 if ( child->_prev ) {
832 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 if ( child->_next ) {
835 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
Lee Thomason8a763612017-06-16 09:30:16 -0700837 child->_next = 0;
838 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700839 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800840}
841
842
U-Stream\Leeae25a442012-02-17 17:48:16 -0800843void XMLNode::DeleteChild( XMLNode* node )
844{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300845 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300846 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100848 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700849 TIXMLASSERT(node->_prev == 0);
850 TIXMLASSERT(node->_next == 0);
851 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400852 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800853}
854
855
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
857{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300858 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300859 if ( addThis->_document != _document ) {
860 TIXMLASSERT( false );
861 return 0;
862 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800863 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700864
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 if ( _lastChild ) {
866 TIXMLASSERT( _firstChild );
867 TIXMLASSERT( _lastChild->_next == 0 );
868 _lastChild->_next = addThis;
869 addThis->_prev = _lastChild;
870 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
874 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 TIXMLASSERT( _firstChild == 0 );
876 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 addThis->_prev = 0;
879 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800883}
884
885
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
887{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300888 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300889 if ( addThis->_document != _document ) {
890 TIXMLASSERT( false );
891 return 0;
892 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800893 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700894
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 if ( _firstChild ) {
896 TIXMLASSERT( _lastChild );
897 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 _firstChild->_prev = addThis;
900 addThis->_next = _firstChild;
901 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800902
Lee Thomason624d43f2012-10-12 10:58:48 -0700903 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 }
905 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 TIXMLASSERT( _lastChild == 0 );
907 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800908
Lee Thomason624d43f2012-10-12 10:58:48 -0700909 addThis->_prev = 0;
910 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700912 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400913 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800914}
915
916
917XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
918{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300919 TIXMLASSERT( addThis );
920 if ( addThis->_document != _document ) {
921 TIXMLASSERT( false );
922 return 0;
923 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700924
Dmitry-Meabb2d042014-12-09 12:59:31 +0300925 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700926
Lee Thomason624d43f2012-10-12 10:58:48 -0700927 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300928 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 return 0;
930 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300931 if ( afterThis == addThis ) {
932 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
933 // Now AddThis must disappear from it's location and then
934 // reappear between BeforeThis and OneAfterAddThis.
935 // So just leave it where it is.
936 return addThis;
937 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800938
Lee Thomason624d43f2012-10-12 10:58:48 -0700939 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 // The last node or the only node.
941 return InsertEndChild( addThis );
942 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800943 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 addThis->_prev = afterThis;
945 addThis->_next = afterThis->_next;
946 afterThis->_next->_prev = addThis;
947 afterThis->_next = addThis;
948 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800950}
951
952
953
954
Dmitry-Me886ad972015-07-22 11:00:51 +0300955const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800956{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300957 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300958 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300960 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 }
962 }
963 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800964}
965
966
Dmitry-Me886ad972015-07-22 11:00:51 +0300967const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800968{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300969 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300970 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300972 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 }
974 }
975 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800976}
977
978
Dmitry-Me886ad972015-07-22 11:00:51 +0300979const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800980{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300981 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300982 const XMLElement* element = node->ToElementWithName( name );
983 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400984 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 }
986 }
987 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800988}
989
990
Dmitry-Me886ad972015-07-22 11:00:51 +0300991const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800992{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300993 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300994 const XMLElement* element = node->ToElementWithName( name );
995 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400996 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
998 }
999 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001000}
1001
1002
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001003char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001004{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 // This is a recursive method, but thinking about it "at the current level"
1006 // it is a pretty simple flat list:
1007 // <foo/>
1008 // <!-- comment -->
1009 //
1010 // With a special case:
1011 // <foo>
1012 // </foo>
1013 // <!-- comment -->
1014 //
1015 // Where the closing element (/foo) *must* be the next thing after the opening
1016 // element, and the names must match. BUT the tricky bit is that the closing
1017 // element will be read by the child.
1018 //
1019 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1020 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021
Lee Thomasond946dda2018-04-05 09:11:08 -07001022 XMLDocument::DepthTracker tracker(_document);
1023 if (_document->Error())
1024 return 0;
1025
1026 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001028
Lee Thomason624d43f2012-10-12 10:58:48 -07001029 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001030 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001031 if ( node == 0 ) {
1032 break;
1033 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001034
orbitcowboy0e7f2892019-01-15 11:28:49 +01001035 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001036
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001038 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001040 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001041 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001042 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 break;
1045 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046
orbitcowboy0e7f2892019-01-15 11:28:49 +01001047 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301048 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001049 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001050 //
1051 // Multiple declarations are allowed but all declarations
1052 // must occur before anything else.
1053 //
1054 // Optimized due to a security test case. If the first node is
1055 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001056 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001057 bool wellLocated = false;
1058
1059 if (ToDocument()) {
1060 if (FirstChild()) {
1061 wellLocated =
1062 FirstChild() &&
1063 FirstChild()->ToDeclaration() &&
1064 LastChild() &&
1065 LastChild()->ToDeclaration();
1066 }
1067 else {
1068 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301069 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001070 }
1071 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001072 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001073 DeleteNode( node );
1074 break;
1075 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301076 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301077
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001078 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001080 // We read the end tag. Return it to the parent.
1081 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001082 if ( parentEndTag ) {
1083 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001084 }
1085 node->_memPool->SetTracked(); // created and then immediately deleted.
1086 DeleteNode( node );
1087 return p;
1088 }
1089
1090 // Handle an end tag returned to this level.
1091 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001092 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001093 if ( endTag.Empty() ) {
1094 if ( ele->ClosingType() == XMLElement::OPEN ) {
1095 mismatch = true;
1096 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001098 else {
1099 if ( ele->ClosingType() != XMLElement::OPEN ) {
1100 mismatch = true;
1101 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001102 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001103 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
1105 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001106 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001107 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001108 DeleteNode( node );
1109 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001110 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
JayXondbfdd8f2014-12-12 20:07:14 -05001112 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 }
1114 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001115}
1116
Lee Thomason816d3fa2017-06-05 14:35:55 -07001117/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001118{
1119 if ( node == 0 ) {
1120 return;
1121 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001122 TIXMLASSERT(node->_document);
1123 if (!node->ToDocument()) {
1124 node->_document->MarkInUse(node);
1125 }
1126
Dmitry-Mee3225b12014-09-03 11:03:11 +04001127 MemPool* pool = node->_memPool;
1128 node->~XMLNode();
1129 pool->Free( node );
1130}
1131
Lee Thomason3cebdc42015-01-05 17:16:28 -08001132void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001133{
1134 TIXMLASSERT( insertThis );
1135 TIXMLASSERT( insertThis->_document == _document );
1136
Lee Thomason816d3fa2017-06-05 14:35:55 -07001137 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001138 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001139 }
1140 else {
1141 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001142 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001143 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001144}
1145
Dmitry-Meecb9b072016-10-12 16:44:59 +03001146const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1147{
1148 const XMLElement* element = this->ToElement();
1149 if ( element == 0 ) {
1150 return 0;
1151 }
1152 if ( name == 0 ) {
1153 return element;
1154 }
1155 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1156 return element;
1157 }
1158 return 0;
1159}
1160
Lee Thomason5492a1c2012-01-23 15:32:10 -08001161// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001162char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001165 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001167 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 }
1169 return p;
1170 }
1171 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001172 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1173 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001174 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001176
kezenator4f756162016-11-29 19:46:27 +10001177 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 if ( p && *p ) {
1179 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001180 }
1181 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001182 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 }
1184 }
1185 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001186}
1187
1188
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001189XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001192 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 }
1194 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1195 text->SetCData( this->CData() );
1196 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001197}
1198
1199
1200bool XMLText::ShallowEqual( const XMLNode* compare ) const
1201{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001202 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001203 const XMLText* text = compare->ToText();
1204 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001205}
1206
1207
Lee Thomason56bdd022012-02-09 18:16:58 -08001208bool XMLText::Accept( XMLVisitor* visitor ) const
1209{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001210 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001212}
1213
1214
Lee Thomason3f57d272012-01-11 15:30:03 -08001215// --------- XMLComment ---------- //
1216
Lee Thomasone4422302012-01-20 17:59:50 -08001217XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001218{
1219}
1220
1221
Lee Thomasonce0763e2012-01-11 15:43:54 -08001222XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001223{
Lee Thomason3f57d272012-01-11 15:30:03 -08001224}
1225
1226
kezenator4f756162016-11-29 19:46:27 +10001227char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001230 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001232 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 }
1234 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001235}
1236
1237
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001238XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1239{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 }
1243 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1244 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245}
1246
1247
1248bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1249{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001250 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001251 const XMLComment* comment = compare->ToComment();
1252 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001253}
1254
1255
Lee Thomason751da522012-02-10 08:50:51 -08001256bool XMLComment::Accept( XMLVisitor* visitor ) const
1257{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001258 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001260}
Lee Thomason56bdd022012-02-09 18:16:58 -08001261
1262
Lee Thomason50f97b22012-02-11 16:33:40 -08001263// --------- XMLDeclaration ---------- //
1264
1265XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1266{
1267}
1268
1269
1270XMLDeclaration::~XMLDeclaration()
1271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001273}
1274
1275
kezenator4f756162016-11-29 19:46:27 +10001276char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001279 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001281 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 }
1283 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001284}
1285
1286
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001287XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001290 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 }
1292 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1293 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001294}
1295
1296
1297bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1298{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001299 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001300 const XMLDeclaration* declaration = compare->ToDeclaration();
1301 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001302}
1303
1304
1305
Lee Thomason50f97b22012-02-11 16:33:40 -08001306bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1307{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001308 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001310}
1311
1312// --------- XMLUnknown ---------- //
1313
1314XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1315{
1316}
1317
1318
1319XMLUnknown::~XMLUnknown()
1320{
1321}
1322
1323
kezenator4f756162016-11-29 19:46:27 +10001324char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001325{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001327 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001329 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001332}
1333
1334
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001335XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001338 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 }
1340 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1341 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001342}
1343
1344
1345bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1346{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001347 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001348 const XMLUnknown* unknown = compare->ToUnknown();
1349 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001350}
1351
1352
Lee Thomason50f97b22012-02-11 16:33:40 -08001353bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1354{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001355 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001357}
1358
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001359// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001360
Gumichan010f1fa6d2018-02-01 14:16:24 +01001361const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001362{
1363 return _name.GetStr();
1364}
1365
Gumichan010f1fa6d2018-02-01 14:16:24 +01001366const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001367{
1368 return _value.GetStr();
1369}
1370
kezenator4f756162016-11-29 19:46:27 +10001371char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001374 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 if ( !p || !*p ) {
1376 return 0;
1377 }
Lee Thomason22aead12012-01-23 13:29:35 -08001378
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001380 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001381 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 return 0;
1383 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001384
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001386 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 if ( *p != '\"' && *p != '\'' ) {
1388 return 0;
1389 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001390
orbitcowboy0e7f2892019-01-15 11:28:49 +01001391 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001393
kezenator4f756162016-11-29 19:46:27 +10001394 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001396}
1397
1398
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001399void XMLAttribute::SetName( const char* n )
1400{
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001402}
1403
1404
Lee Thomason2fa81722012-11-09 12:37:46 -08001405XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001408 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 }
1410 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001411}
1412
1413
Lee Thomason2fa81722012-11-09 12:37:46 -08001414XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001417 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001420}
1421
1422
Lee Thomason51c12712016-06-04 20:18:49 -07001423XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1424{
1425 if (XMLUtil::ToInt64(Value(), value)) {
1426 return XML_SUCCESS;
1427 }
1428 return XML_WRONG_ATTRIBUTE_TYPE;
1429}
1430
1431
cugone75a5acc2019-04-11 22:03:43 -05001432XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1433{
1434 if(XMLUtil::ToUnsigned64(Value(), value)) {
1435 return XML_SUCCESS;
1436 }
1437 return XML_WRONG_ATTRIBUTE_TYPE;
1438}
1439
1440
Lee Thomason2fa81722012-11-09 12:37:46 -08001441XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001444 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 }
1446 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001447}
1448
1449
Lee Thomason2fa81722012-11-09 12:37:46 -08001450XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001453 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
1455 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001456}
1457
1458
Lee Thomason2fa81722012-11-09 12:37:46 -08001459XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001462 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001465}
1466
1467
1468void XMLAttribute::SetAttribute( const char* v )
1469{
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001471}
1472
1473
Lee Thomason1ff38e02012-02-14 18:18:16 -08001474void XMLAttribute::SetAttribute( int v )
1475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 char buf[BUF_SIZE];
1477 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001479}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001480
1481
1482void XMLAttribute::SetAttribute( unsigned v )
1483{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 char buf[BUF_SIZE];
1485 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487}
1488
1489
Lee Thomason51c12712016-06-04 20:18:49 -07001490void XMLAttribute::SetAttribute(int64_t v)
1491{
1492 char buf[BUF_SIZE];
1493 XMLUtil::ToStr(v, buf, BUF_SIZE);
1494 _value.SetStr(buf);
1495}
1496
Lee Thomasoneffdf952019-08-10 17:49:42 -07001497void XMLAttribute::SetAttribute(uint64_t v)
1498{
1499 char buf[BUF_SIZE];
1500 XMLUtil::ToStr(v, buf, BUF_SIZE);
1501 _value.SetStr(buf);
1502}
Lee Thomason51c12712016-06-04 20:18:49 -07001503
1504
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505void XMLAttribute::SetAttribute( bool v )
1506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 char buf[BUF_SIZE];
1508 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001510}
1511
1512void XMLAttribute::SetAttribute( double 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( float 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
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001526
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001527// --------- XMLElement ---------- //
1528XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001529 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001531{
1532}
1533
1534
1535XMLElement::~XMLElement()
1536{
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 while( _rootAttribute ) {
1538 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001539 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001542}
1543
1544
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001545const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1546{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001547 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1549 return a;
1550 }
1551 }
1552 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001553}
1554
1555
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001556const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 const XMLAttribute* a = FindAttribute( name );
1559 if ( !a ) {
1560 return 0;
1561 }
1562 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1563 return a->Value();
1564 }
1565 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001566}
1567
Gumichan010f1fa6d2018-02-01 14:16:24 +01001568int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001569{
1570 int i = defaultValue;
1571 QueryIntAttribute(name, &i);
1572 return i;
1573}
1574
Gumichan010f1fa6d2018-02-01 14:16:24 +01001575unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001576{
1577 unsigned i = defaultValue;
1578 QueryUnsignedAttribute(name, &i);
1579 return i;
1580}
1581
Gumichan010f1fa6d2018-02-01 14:16:24 +01001582int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001583{
1584 int64_t i = defaultValue;
1585 QueryInt64Attribute(name, &i);
1586 return i;
1587}
1588
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01001589uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1590{
1591 uint64_t i = defaultValue;
1592 QueryUnsigned64Attribute(name, &i);
1593 return i;
1594}
1595
Gumichan010f1fa6d2018-02-01 14:16:24 +01001596bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001597{
1598 bool b = defaultValue;
1599 QueryBoolAttribute(name, &b);
1600 return b;
1601}
1602
Gumichan010f1fa6d2018-02-01 14:16:24 +01001603double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001604{
1605 double d = defaultValue;
1606 QueryDoubleAttribute(name, &d);
1607 return d;
1608}
1609
Gumichan010f1fa6d2018-02-01 14:16:24 +01001610float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001611{
1612 float f = defaultValue;
1613 QueryFloatAttribute(name, &f);
1614 return f;
1615}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001616
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001617const char* XMLElement::GetText() const
1618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001620 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001623}
1624
1625
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001626void XMLElement::SetText( const char* inText )
1627{
Uli Kusterer869bb592014-01-21 01:36:16 +01001628 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001629 FirstChild()->SetValue( inText );
1630 else {
1631 XMLText* theText = GetDocument()->NewText( inText );
1632 InsertFirstChild( theText );
1633 }
1634}
1635
Lee Thomason5bb2d802014-01-24 10:42:57 -08001636
Gumichan010f1fa6d2018-02-01 14:16:24 +01001637void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001638{
1639 char buf[BUF_SIZE];
1640 XMLUtil::ToStr( v, buf, BUF_SIZE );
1641 SetText( buf );
1642}
1643
1644
Gumichan010f1fa6d2018-02-01 14:16:24 +01001645void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001646{
1647 char buf[BUF_SIZE];
1648 XMLUtil::ToStr( v, buf, BUF_SIZE );
1649 SetText( buf );
1650}
1651
1652
Lee Thomason51c12712016-06-04 20:18:49 -07001653void XMLElement::SetText(int64_t v)
1654{
1655 char buf[BUF_SIZE];
1656 XMLUtil::ToStr(v, buf, BUF_SIZE);
1657 SetText(buf);
1658}
1659
cugone47e229e2019-04-12 17:27:28 -05001660void XMLElement::SetText(uint64_t v) {
1661 char buf[BUF_SIZE];
1662 XMLUtil::ToStr(v, buf, BUF_SIZE);
1663 SetText(buf);
1664}
1665
Lee Thomason51c12712016-06-04 20:18:49 -07001666
1667void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001668{
1669 char buf[BUF_SIZE];
1670 XMLUtil::ToStr( v, buf, BUF_SIZE );
1671 SetText( buf );
1672}
1673
1674
Gumichan010f1fa6d2018-02-01 14:16:24 +01001675void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001676{
1677 char buf[BUF_SIZE];
1678 XMLUtil::ToStr( v, buf, BUF_SIZE );
1679 SetText( buf );
1680}
1681
1682
Gumichan010f1fa6d2018-02-01 14:16:24 +01001683void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001684{
1685 char buf[BUF_SIZE];
1686 XMLUtil::ToStr( v, buf, BUF_SIZE );
1687 SetText( buf );
1688}
1689
1690
MortenMacFly4ee49f12013-01-14 20:03:14 +01001691XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001694 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001695 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 return XML_SUCCESS;
1697 }
1698 return XML_CAN_NOT_CONVERT_TEXT;
1699 }
1700 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001701}
1702
1703
MortenMacFly4ee49f12013-01-14 20:03:14 +01001704XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001705{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001707 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001708 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 return XML_SUCCESS;
1710 }
1711 return XML_CAN_NOT_CONVERT_TEXT;
1712 }
1713 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001714}
1715
1716
Lee Thomason51c12712016-06-04 20:18:49 -07001717XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1718{
1719 if (FirstChild() && FirstChild()->ToText()) {
1720 const char* t = FirstChild()->Value();
1721 if (XMLUtil::ToInt64(t, ival)) {
1722 return XML_SUCCESS;
1723 }
1724 return XML_CAN_NOT_CONVERT_TEXT;
1725 }
1726 return XML_NO_TEXT_NODE;
1727}
1728
1729
cugone1dbfe312019-04-12 17:33:49 -05001730XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const
1731{
cugone47e229e2019-04-12 17:27:28 -05001732 if(FirstChild() && FirstChild()->ToText()) {
1733 const char* t = FirstChild()->Value();
1734 if(XMLUtil::ToUnsigned64(t, ival)) {
1735 return XML_SUCCESS;
1736 }
1737 return XML_CAN_NOT_CONVERT_TEXT;
1738 }
1739 return XML_NO_TEXT_NODE;
1740}
1741
1742
MortenMacFly4ee49f12013-01-14 20:03:14 +01001743XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001744{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001746 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001747 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 return XML_SUCCESS;
1749 }
1750 return XML_CAN_NOT_CONVERT_TEXT;
1751 }
1752 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001753}
1754
1755
MortenMacFly4ee49f12013-01-14 20:03:14 +01001756XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001757{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001759 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001760 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 return XML_SUCCESS;
1762 }
1763 return XML_CAN_NOT_CONVERT_TEXT;
1764 }
1765 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001766}
1767
1768
MortenMacFly4ee49f12013-01-14 20:03:14 +01001769XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001770{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001772 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001773 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 return XML_SUCCESS;
1775 }
1776 return XML_CAN_NOT_CONVERT_TEXT;
1777 }
1778 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001779}
1780
Josh Wittnercf3dd092016-10-11 18:57:17 -07001781int XMLElement::IntText(int defaultValue) const
1782{
1783 int i = defaultValue;
1784 QueryIntText(&i);
1785 return i;
1786}
1787
1788unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1789{
1790 unsigned i = defaultValue;
1791 QueryUnsignedText(&i);
1792 return i;
1793}
1794
1795int64_t XMLElement::Int64Text(int64_t defaultValue) const
1796{
1797 int64_t i = defaultValue;
1798 QueryInt64Text(&i);
1799 return i;
1800}
1801
cugone1dbfe312019-04-12 17:33:49 -05001802uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1803{
1804 uint64_t i = defaultValue;
1805 QueryUnsigned64Text(&i);
1806 return i;
1807}
1808
Josh Wittnercf3dd092016-10-11 18:57:17 -07001809bool XMLElement::BoolText(bool defaultValue) const
1810{
1811 bool b = defaultValue;
1812 QueryBoolText(&b);
1813 return b;
1814}
1815
1816double XMLElement::DoubleText(double defaultValue) const
1817{
1818 double d = defaultValue;
1819 QueryDoubleText(&d);
1820 return d;
1821}
1822
1823float XMLElement::FloatText(float defaultValue) const
1824{
1825 float f = defaultValue;
1826 QueryFloatText(&f);
1827 return f;
1828}
Lee Thomason21be8822012-07-15 17:27:22 -07001829
1830
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001831XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1832{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 XMLAttribute* last = 0;
1834 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1839 break;
1840 }
1841 }
1842 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001843 attrib = CreateAttribute();
1844 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001846 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 }
1849 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001850 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
1853 attrib->SetName( name );
1854 }
1855 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001856}
1857
1858
U-Stream\Leeae25a442012-02-17 17:48:16 -08001859void XMLElement::DeleteAttribute( const char* name )
1860{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1864 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 }
1867 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001870 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 break;
1872 }
1873 prev = a;
1874 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001875}
1876
1877
kezenator4f756162016-11-29 19:46:27 +10001878char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001879{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001881
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 // Read the attributes.
1883 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001884 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001885 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001886 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 return 0;
1888 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001889
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001891 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001892 XMLAttribute* attrib = CreateAttribute();
1893 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001894 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001895
orbitcowboy0e7f2892019-01-15 11:28:49 +01001896 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001897
kezenator4f756162016-11-29 19:46:27 +10001898 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001900 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001901 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 return 0;
1903 }
1904 // There is a minor bug here: if the attribute in the source xml
1905 // document is duplicated, it will not be detected and the
1906 // attribute will be doubly added. However, tracking the 'prevAttribute'
1907 // avoids re-scanning the attribute list. Preferring performance for
1908 // now, may reconsider in the future.
1909 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001910 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 }
1913 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001914 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 }
1917 prevAttribute = attrib;
1918 }
1919 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 else if ( *p == '>' ) {
1921 ++p;
1922 break;
1923 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001924 // end of the tag
1925 else if ( *p == '/' && *(p+1) == '>' ) {
1926 _closingType = CLOSED;
1927 return p+2; // done; sealed element.
1928 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001930 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 return 0;
1932 }
1933 }
1934 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001935}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001936
Dmitry-Mee3225b12014-09-03 11:03:11 +04001937void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1938{
1939 if ( attribute == 0 ) {
1940 return;
1941 }
1942 MemPool* pool = attribute->_memPool;
1943 attribute->~XMLAttribute();
1944 pool->Free( attribute );
1945}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001946
Dmitry-Mea60caa22016-11-22 18:28:08 +03001947XMLAttribute* XMLElement::CreateAttribute()
1948{
1949 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1950 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001951 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001952 attrib->_memPool = &_document->_attributePool;
1953 attrib->_memPool->SetTracked();
1954 return attrib;
1955}
1956
Lee Thomason67d61312012-01-24 16:01:51 -08001957//
1958// <ele></ele>
1959// <ele>foo<b>bar</b></ele>
1960//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001961char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001964 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001965
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 // The closing element is the </element> form. It is
1967 // parsed just like a regular element then deleted from
1968 // the DOM.
1969 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 ++p;
1972 }
Lee Thomason67d61312012-01-24 16:01:51 -08001973
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 p = _value.ParseName( p );
1975 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 return 0;
1977 }
Lee Thomason67d61312012-01-24 16:01:51 -08001978
kezenator4f756162016-11-29 19:46:27 +10001979 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001980 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 return p;
1982 }
Lee Thomason67d61312012-01-24 16:01:51 -08001983
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001984 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001986}
1987
1988
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001989
1990XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 }
1995 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1996 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1997 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1998 }
1999 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002000}
2001
2002
2003bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2004{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002005 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03002007 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002008
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 const XMLAttribute* a=FirstAttribute();
2010 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002011
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 while ( a && b ) {
2013 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2014 return false;
2015 }
2016 a = a->Next();
2017 b = b->Next();
2018 }
2019 if ( a || b ) {
2020 // different count
2021 return false;
2022 }
2023 return true;
2024 }
2025 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002026}
2027
2028
Lee Thomason751da522012-02-10 08:50:51 -08002029bool XMLElement::Accept( XMLVisitor* visitor ) const
2030{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002031 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2034 if ( !node->Accept( visitor ) ) {
2035 break;
2036 }
2037 }
2038 }
2039 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08002040}
Lee Thomason56bdd022012-02-09 18:16:58 -08002041
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002042
Lee Thomason3f57d272012-01-11 15:30:03 -08002043// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002044
2045// Warning: List must match 'enum XMLError'
2046const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2047 "XML_SUCCESS",
2048 "XML_NO_ATTRIBUTE",
2049 "XML_WRONG_ATTRIBUTE_TYPE",
2050 "XML_ERROR_FILE_NOT_FOUND",
2051 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2052 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002053 "XML_ERROR_PARSING_ELEMENT",
2054 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002055 "XML_ERROR_PARSING_TEXT",
2056 "XML_ERROR_PARSING_CDATA",
2057 "XML_ERROR_PARSING_COMMENT",
2058 "XML_ERROR_PARSING_DECLARATION",
2059 "XML_ERROR_PARSING_UNKNOWN",
2060 "XML_ERROR_EMPTY_DOCUMENT",
2061 "XML_ERROR_MISMATCHED_ELEMENT",
2062 "XML_ERROR_PARSING",
2063 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002064 "XML_NO_TEXT_NODE",
2065 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002066};
2067
2068
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002069XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002071 _writeBOM( false ),
2072 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002073 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002074 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002075 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002076 _errorLineNum( 0 ),
2077 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002078 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002079 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002080 _unlinked(),
2081 _elementPool(),
2082 _attributePool(),
2083 _textPool(),
2084 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002085{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002086 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2087 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002088}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002089
2090
Lee Thomason3f57d272012-01-11 15:30:03 -08002091XMLDocument::~XMLDocument()
2092{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002093 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002094}
2095
2096
Lee Thomason816d3fa2017-06-05 14:35:55 -07002097void XMLDocument::MarkInUse(XMLNode* node)
2098{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002099 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002100 TIXMLASSERT(node->_parent == 0);
2101
2102 for (int i = 0; i < _unlinked.Size(); ++i) {
2103 if (node == _unlinked[i]) {
2104 _unlinked.SwapRemove(i);
2105 break;
2106 }
2107 }
2108}
2109
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002110void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002111{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002112 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002113 while( _unlinked.Size()) {
2114 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2115 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002116
Peter Matula50689912018-01-09 12:52:26 +01002117#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002118 const bool hadError = Error();
2119#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002120 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002121
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 delete [] _charBuffer;
2123 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002124 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002125
2126#if 0
2127 _textPool.Trace( "text" );
2128 _elementPool.Trace( "element" );
2129 _commentPool.Trace( "comment" );
2130 _attributePool.Trace( "attribute" );
2131#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002132
Peter Matula50689912018-01-09 12:52:26 +01002133#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002134 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002135 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2136 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2137 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2138 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2139 }
2140#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002141}
2142
Lee Thomason3f57d272012-01-11 15:30:03 -08002143
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002144void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002145{
2146 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002147 if (target == this) {
2148 return; // technically success - a no-op.
2149 }
Lee Thomason7085f002017-06-01 18:09:43 -07002150
2151 target->Clear();
2152 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2153 target->InsertEndChild(node->DeepClone(target));
2154 }
2155}
2156
Lee Thomason2c85a712012-01-31 08:24:24 -08002157XMLElement* XMLDocument::NewElement( const char* name )
2158{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002159 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 ele->SetName( name );
2161 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002162}
2163
2164
Lee Thomason1ff38e02012-02-14 18:18:16 -08002165XMLComment* XMLDocument::NewComment( const char* str )
2166{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002167 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 comment->SetValue( str );
2169 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002170}
2171
2172
2173XMLText* XMLDocument::NewText( const char* str )
2174{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002175 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 text->SetValue( str );
2177 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002178}
2179
2180
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002181XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2182{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002183 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2185 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002186}
2187
2188
2189XMLUnknown* XMLDocument::NewUnknown( const char* str )
2190{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002191 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 unk->SetValue( str );
2193 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002194}
2195
Dmitry-Me01578db2014-08-19 10:18:48 +04002196static FILE* callfopen( const char* filepath, const char* mode )
2197{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002198 TIXMLASSERT( filepath );
2199 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002200#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2201 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002202 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002203 if ( err ) {
2204 return 0;
2205 }
2206#else
2207 FILE* fp = fopen( filepath, mode );
2208#endif
2209 return fp;
2210}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002211
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002212void XMLDocument::DeleteNode( XMLNode* node ) {
2213 TIXMLASSERT( node );
2214 TIXMLASSERT(node->_document == this );
2215 if (node->_parent) {
2216 node->_parent->DeleteChild( node );
2217 }
2218 else {
2219 // Isn't in the tree.
2220 // Use the parent delete.
2221 // Also, we need to mark it tracked: we 'know'
2222 // it was never used.
2223 node->_memPool->SetTracked();
2224 // Call the static XMLNode version:
2225 XMLNode::DeleteNode(node);
2226 }
2227}
2228
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002229
Lee Thomason2fa81722012-11-09 12:37:46 -08002230XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002232 if ( !filename ) {
2233 TIXMLASSERT( false );
2234 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2235 return _errorID;
2236 }
2237
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002238 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002239 FILE* fp = callfopen( filename, "rb" );
2240 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002241 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 }
2244 LoadFile( fp );
2245 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002247}
2248
Dmitry-Me901fed52015-09-25 10:29:51 +03002249// This is likely overengineered template art to have a check that unsigned long value incremented
2250// by one still fits into size_t. If size_t type is larger than unsigned long type
2251// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2252// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2253// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2254// types sizes relate to each other.
2255template
2256<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2257struct LongFitsIntoSizeTMinusOne {
2258 static bool Fits( unsigned long value )
2259 {
2260 return value < (size_t)-1;
2261 }
2262};
2263
2264template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002265struct LongFitsIntoSizeTMinusOne<false> {
2266 static bool Fits( unsigned long )
2267 {
2268 return true;
2269 }
2270};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002271
Lee Thomason2fa81722012-11-09 12:37:46 -08002272XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002273{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002274 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002275
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002276 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002277 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002278 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002279 return _errorID;
2280 }
2281
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002283 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002285 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002286 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002287 return _errorID;
2288 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002289 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002290
Dmitry-Me901fed52015-09-25 10:29:51 +03002291 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002292 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002293 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002294 return _errorID;
2295 }
2296
Dmitry-Me72801b82015-05-07 09:41:39 +03002297 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002298 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002299 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002301
Dmitry-Me72801b82015-05-07 09:41:39 +03002302 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002303 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002305 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002307 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002308 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002310
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312
Dmitry-Me97476b72015-01-01 16:15:57 +03002313 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002314 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002315}
2316
2317
Lee Thomason2fa81722012-11-09 12:37:46 -08002318XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002319{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002320 if ( !filename ) {
2321 TIXMLASSERT( false );
2322 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2323 return _errorID;
2324 }
2325
Dmitry-Me01578db2014-08-19 10:18:48 +04002326 FILE* fp = callfopen( filename, "w" );
2327 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002328 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002329 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002330 }
2331 SaveFile(fp, compact);
2332 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002333 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002334}
2335
2336
Lee Thomason2fa81722012-11-09 12:37:46 -08002337XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002338{
Ant Mitchell189198f2015-03-24 16:20:36 +00002339 // Clear any error from the last save, otherwise it will get reported
2340 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002341 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 XMLPrinter stream( fp, compact );
2343 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002344 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002345}
2346
Lee Thomason1ff38e02012-02-14 18:18:16 -08002347
Lee Thomason2fa81722012-11-09 12:37:46 -08002348XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002349{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002350 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002351
Lee Thomason82d32002014-02-21 22:47:18 -08002352 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002353 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 }
2356 if ( len == (size_t)(-1) ) {
2357 len = strlen( p );
2358 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002359 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 _charBuffer = new char[ len+1 ];
2361 memcpy( _charBuffer, p, len );
2362 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002363
Dmitry-Me97476b72015-01-01 16:15:57 +03002364 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002365 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002366 // clean up now essentially dangling memory.
2367 // and the parse fail can put objects in the
2368 // pools that are dead and inaccessible.
2369 DeleteChildren();
2370 _elementPool.Clear();
2371 _attributePool.Clear();
2372 _textPool.Clear();
2373 _commentPool.Clear();
2374 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002376}
2377
2378
PKEuS1c5f99e2013-07-06 11:28:39 +02002379void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002380{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002381 if ( streamer ) {
2382 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002384 else {
2385 XMLPrinter stdoutStreamer( stdout );
2386 Accept( &stdoutStreamer );
2387 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002388}
2389
2390
Lee Thomasonaa188392017-09-19 17:54:31 -07002391void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002392{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002393 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002394 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002395 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002396 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002397
orbitcowboy0e7f2892019-01-15 11:28:49 +01002398 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002399 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002400
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002401 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002402 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 -07002403
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002404 if (format) {
2405 size_t len = strlen(buffer);
2406 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2407 len = strlen(buffer);
2408
2409 va_list va;
2410 va_start(va, format);
2411 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2412 va_end(va);
2413 }
2414 _errorStr.SetStr(buffer);
2415 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002416}
2417
Lee Thomasonaa188392017-09-19 17:54:31 -07002418
Lee Thomasone90e9012016-12-24 07:34:39 -08002419/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002420{
kezenator5a700712016-11-26 13:54:42 +10002421 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2422 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002423 TIXMLASSERT( errorName && errorName[0] );
2424 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002425}
Lee Thomason5cae8972012-01-24 18:03:07 -08002426
Gumichan010f1fa6d2018-02-01 14:16:24 +01002427const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002428{
Lee Thomasonaa188392017-09-19 17:54:31 -07002429 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002430}
2431
Lee Thomasonf49b9652017-10-11 10:57:49 -07002432
2433void XMLDocument::PrintError() const
2434{
2435 printf("%s\n", ErrorStr());
2436}
2437
kezenator5a700712016-11-26 13:54:42 +10002438const char* XMLDocument::ErrorName() const
2439{
Lee Thomasone90e9012016-12-24 07:34:39 -08002440 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002441}
2442
Dmitry-Me97476b72015-01-01 16:15:57 +03002443void XMLDocument::Parse()
2444{
2445 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2446 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002447 _parseCurLineNum = 1;
2448 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002449 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002450 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002451 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002452 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002453 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002454 return;
2455 }
kezenator4f756162016-11-29 19:46:27 +10002456 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002457}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002458
Lee Thomasonf928c352018-04-05 09:24:20 -07002459void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002460{
2461 _parsingDepth++;
2462 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002463 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002464 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002465}
2466
Lee Thomasonf928c352018-04-05 09:24:20 -07002467void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002468{
2469 TIXMLASSERT(_parsingDepth > 0);
2470 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002471}
2472
PKEuS1bfb9542013-08-04 13:51:17 +02002473XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002474 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002475 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002476 _firstElement( true ),
2477 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002478 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002479 _textDepth( -1 ),
2480 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002481 _compactMode( compact ),
2482 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002483{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002484 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002485 _entityFlag[i] = false;
2486 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002487 }
2488 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002489 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002490 const unsigned char flagIndex = (unsigned char)entityValue;
2491 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2492 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002493 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002494 _restrictedEntityFlag[(unsigned char)'&'] = true;
2495 _restrictedEntityFlag[(unsigned char)'<'] = true;
2496 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002497 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002498}
2499
2500
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002501void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002502{
2503 va_list va;
2504 va_start( va, format );
2505
Lee Thomason624d43f2012-10-12 10:58:48 -07002506 if ( _fp ) {
2507 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 }
2509 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002510 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002511 // Close out and re-start the va-args
2512 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002513 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002515 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002516 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002517 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002519 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002520}
2521
2522
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002523void XMLPrinter::Write( const char* data, size_t size )
2524{
2525 if ( _fp ) {
2526 fwrite ( data , sizeof(char), size, _fp);
2527 }
2528 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002529 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002530 memcpy( p, data, size );
2531 p[size] = 0;
2532 }
2533}
2534
2535
2536void XMLPrinter::Putc( char ch )
2537{
2538 if ( _fp ) {
2539 fputc ( ch, _fp);
2540 }
2541 else {
2542 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2543 p[0] = ch;
2544 p[1] = 0;
2545 }
2546}
2547
2548
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002549void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002550{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002552 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002553 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002554}
2555
2556
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002557void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002559 // Look for runs of bytes between entities to print.
2560 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002561
Lee Thomason624d43f2012-10-12 10:58:48 -07002562 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002563 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002564 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002565 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002566 // Remember, char is sometimes signed. (How many times has that bitten me?)
2567 if ( *q > 0 && *q < ENTITY_RANGE ) {
2568 // Check for entities. If one is found, flush
2569 // the stream up until the entity, write the
2570 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002571 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002573 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002574 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002575 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002576 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002577 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002578 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 for( int i=0; i<NUM_ENTITIES; ++i ) {
2580 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002581 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002582 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002583 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002584 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002585 break;
2586 }
2587 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002588 if ( !entityPatternPrinted ) {
2589 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2590 TIXMLASSERT( false );
2591 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002592 ++p;
2593 }
2594 }
2595 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002596 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002597 }
Derek Quambe69ae62018-04-18 13:40:46 -05002598 // Flush the remaining string. This will be the entire
2599 // string if an entity wasn't found.
2600 if ( p < q ) {
2601 const size_t delta = q - p;
2602 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2603 Write( p, toPrint );
2604 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 }
Derek Quambe69ae62018-04-18 13:40:46 -05002606 else {
2607 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002608 }
Lee Thomason857b8682012-01-25 17:50:25 -08002609}
2610
U-Stream\Leeae25a442012-02-17 17:48:16 -08002611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002612void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002614 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002615 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 +03002616 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 }
2618 if ( writeDec ) {
2619 PushDeclaration( "xml version=\"1.0\"" );
2620 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002621}
2622
2623
Uli Kusterer593a33d2014-02-01 12:48:51 +01002624void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002625{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002626 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002627 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002628
Uli Kusterer593a33d2014-02-01 12:48:51 +01002629 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002630 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002631 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002632 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002633 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002634 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002635
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002636 Write ( "<" );
2637 Write ( name );
2638
Lee Thomason624d43f2012-10-12 10:58:48 -07002639 _elementJustOpened = true;
2640 _firstElement = false;
2641 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002642}
2643
2644
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002645void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002646{
Lee Thomason624d43f2012-10-12 10:58:48 -07002647 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002648 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002649 Write( name );
2650 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002652 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002653}
2654
2655
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002656void XMLPrinter::PushAttribute( const char* name, int v )
2657{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002658 char buf[BUF_SIZE];
2659 XMLUtil::ToStr( v, buf, BUF_SIZE );
2660 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002661}
2662
2663
2664void XMLPrinter::PushAttribute( const char* name, unsigned v )
2665{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 char buf[BUF_SIZE];
2667 XMLUtil::ToStr( v, buf, BUF_SIZE );
2668 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002669}
2670
2671
Lee Thomason51c12712016-06-04 20:18:49 -07002672void XMLPrinter::PushAttribute(const char* name, int64_t v)
2673{
2674 char buf[BUF_SIZE];
2675 XMLUtil::ToStr(v, buf, BUF_SIZE);
2676 PushAttribute(name, buf);
2677}
2678
2679
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002680void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2681{
2682 char buf[BUF_SIZE];
2683 XMLUtil::ToStr(v, buf, BUF_SIZE);
2684 PushAttribute(name, buf);
2685}
2686
2687
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002688void XMLPrinter::PushAttribute( const char* name, bool v )
2689{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002690 char buf[BUF_SIZE];
2691 XMLUtil::ToStr( v, buf, BUF_SIZE );
2692 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002693}
2694
2695
2696void XMLPrinter::PushAttribute( const char* name, double v )
2697{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002698 char buf[BUF_SIZE];
2699 XMLUtil::ToStr( v, buf, BUF_SIZE );
2700 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002701}
2702
2703
Uli Kustererca412e82014-02-01 13:35:05 +01002704void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002705{
Lee Thomason624d43f2012-10-12 10:58:48 -07002706 --_depth;
2707 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002708
Lee Thomason624d43f2012-10-12 10:58:48 -07002709 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002710 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 }
2712 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002713 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002714 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002715 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002716 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002717 Write ( "</" );
2718 Write ( name );
2719 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002720 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002721
Lee Thomason624d43f2012-10-12 10:58:48 -07002722 if ( _textDepth == _depth ) {
2723 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002724 }
Uli Kustererca412e82014-02-01 13:35:05 +01002725 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002726 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002727 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002728 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002729}
2730
2731
Dmitry-Mea092bc12014-12-23 17:57:05 +03002732void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002733{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002734 if ( !_elementJustOpened ) {
2735 return;
2736 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002737 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002738 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002739}
2740
2741
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002742void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002743{
Lee Thomason624d43f2012-10-12 10:58:48 -07002744 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002745
Dmitry-Mea092bc12014-12-23 17:57:05 +03002746 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002747 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002748 Write( "<![CDATA[" );
2749 Write( text );
2750 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002751 }
2752 else {
2753 PrintString( text, true );
2754 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002755}
2756
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002757
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002758void XMLPrinter::PushText( int64_t value )
2759{
2760 char buf[BUF_SIZE];
2761 XMLUtil::ToStr( value, buf, BUF_SIZE );
2762 PushText( buf, false );
2763}
2764
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002765
2766void XMLPrinter::PushText( uint64_t value )
2767{
2768 char buf[BUF_SIZE];
2769 XMLUtil::ToStr(value, buf, BUF_SIZE);
2770 PushText(buf, false);
2771}
2772
2773
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002774void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002775{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002776 char buf[BUF_SIZE];
2777 XMLUtil::ToStr( value, buf, BUF_SIZE );
2778 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002779}
2780
2781
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002782void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002783{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002784 char buf[BUF_SIZE];
2785 XMLUtil::ToStr( value, buf, BUF_SIZE );
2786 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002787}
2788
2789
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002790void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002791{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002792 char buf[BUF_SIZE];
2793 XMLUtil::ToStr( value, buf, BUF_SIZE );
2794 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002795}
2796
2797
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002798void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002799{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002800 char buf[BUF_SIZE];
2801 XMLUtil::ToStr( value, buf, BUF_SIZE );
2802 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002803}
2804
2805
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002806void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002807{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002808 char buf[BUF_SIZE];
2809 XMLUtil::ToStr( value, buf, BUF_SIZE );
2810 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002811}
2812
Lee Thomason5cae8972012-01-24 18:03:07 -08002813
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002814void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002815{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002816 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002817 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002818 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002819 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002820 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002821 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002822
2823 Write( "<!--" );
2824 Write( comment );
2825 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002826}
Lee Thomason751da522012-02-10 08:50:51 -08002827
2828
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002829void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002830{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002831 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002832 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002833 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002834 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002835 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002836 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002837
2838 Write( "<?" );
2839 Write( value );
2840 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002841}
2842
2843
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002844void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002845{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002846 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002847 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002848 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002849 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002850 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002851 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002852
2853 Write( "<!" );
2854 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002855 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002856}
2857
2858
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002859bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002860{
Lee Thomason624d43f2012-10-12 10:58:48 -07002861 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002862 if ( doc.HasBOM() ) {
2863 PushHeader( true, false );
2864 }
2865 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002866}
2867
2868
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002869bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002870{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002871 const XMLElement* parentElem = 0;
2872 if ( element.Parent() ) {
2873 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002874 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002875 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002876 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002877 while ( attribute ) {
2878 PushAttribute( attribute->Name(), attribute->Value() );
2879 attribute = attribute->Next();
2880 }
2881 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002882}
2883
2884
Uli Kustererca412e82014-02-01 13:35:05 +01002885bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002886{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002887 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002888 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002889}
2890
2891
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002892bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002893{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002894 PushText( text.Value(), text.CData() );
2895 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002896}
2897
2898
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002899bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002901 PushComment( comment.Value() );
2902 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002903}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002904
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002905bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002907 PushDeclaration( declaration.Value() );
2908 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002909}
2910
2911
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002912bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002914 PushUnknown( unknown.Value() );
2915 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002916}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002917
Lee Thomason685b8952012-11-12 13:00:06 -08002918} // namespace tinyxml2