blob: 0467d17dff6b3f66531aeac960642d8353c52e5b [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
orbitcowboy0e7f2892019-01-15 11:28:49 +010048 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070049 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
orbitcowboy0e7f2892019-01-15 11:28:49 +010055 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070056 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
orbitcowboy710a3322019-05-16 15:30:47 +0200104static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
orbitcowboy710a3322019-05-16 15:30:47 +0200106static const char CARRIAGE_RETURN = static_cast<char>(0x0d); // CR gets filtered out
Lee Thomasonfde6a752012-01-14 18:08:12 -0800107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100200 const char endChar = *endTag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 // Inner loop of text parsing.
204 while ( *p ) {
205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
206 Set( start, p, strFlags );
207 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000208 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000209 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 }
211 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300212 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 }
214 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215}
216
217
218char* StrPair::ParseName( char* p )
219{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 return 0;
222 }
JayXonee525db2014-12-24 04:01:42 -0500223 if ( !XMLUtil::IsNameStartChar( *p ) ) {
224 return 0;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400227 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500228 ++p;
229 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 ++p;
231 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800232
JayXonee525db2014-12-24 04:01:42 -0500233 Set( start, p, 0 );
234 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235}
236
237
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238void StrPair::CollapseWhitespace()
239{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400240 // Adjusting _start would cause undefined behavior on delete[]
241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300245 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300246 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700248
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700249 while( *p ) {
250 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800251 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 if ( *p == 0 ) {
253 break; // don't write to q; this trims the trailing space.
254 }
255 *q = ' ';
256 ++q;
257 }
258 *q = *p;
259 ++q;
260 ++p;
261 }
262 *q = 0;
263 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700264}
265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267const char* StrPair::GetStr()
268{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300269 TIXMLASSERT( _start );
270 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags & NEEDS_FLUSH ) {
272 *_end = 0;
273 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300276 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700277 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800278
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 while( p < _end ) {
280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 // CR-LF pair becomes LF
282 // CR alone becomes LF
283 // LF-CR becomes LF
284 if ( *(p+1) == LF ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300290 *q = LF;
291 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 if ( *(p+1) == CR ) {
295 p += 2;
296 }
297 else {
298 ++p;
299 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300300 *q = LF;
301 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 // Entities handled by tinyXML2:
305 // - special entities in the entity table [in/out]
306 // - numeric character reference [in]
307 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400310 const int buflen = 10;
311 char buf[buflen] = { 0 };
312 int len = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100313 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me6f51c802015-03-14 13:25:03 +0300314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200433 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200438 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200443 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
orbitcowboy710a3322019-05-16 15:30:47 +0200448 *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
cugone47e229e2019-04-12 17:27:28 -0500585void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
Lee Thomason51c12712016-06-04 20:18:49 -0700586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
orbitcowboy710a3322019-05-16 15:30:47 +0200588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
cugone47e229e2019-04-12 17:27:28 -0500591void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
592{
593 // horrible syntax trick to make the compiler happy about %llu
594 TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
595}
Lee Thomason51c12712016-06-04 20:18:49 -0700596
Lee Thomason21be8822012-07-15 17:27:22 -0700597bool XMLUtil::ToInt( const char* str, int* value )
598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
606{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
608 return true;
609 }
610 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700611}
612
613bool XMLUtil::ToBool( const char* str, bool* value )
614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 int ival = 0;
616 if ( ToInt( str, &ival )) {
617 *value = (ival==0) ? false : true;
618 return true;
619 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700620 static const char* TRUE[] = { "true", "True", "TRUE", 0 };
621 static const char* FALSE[] = { "false", "False", "FALSE", 0 };
622
623 for (int i = 0; TRUE[i]; ++i) {
624 if (StringEqual(str, TRUE[i])) {
625 *value = true;
626 return true;
627 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700629 for (int i = 0; FALSE[i]; ++i) {
630 if (StringEqual(str, FALSE[i])) {
631 *value = false;
632 return true;
633 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
635 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700636}
637
638
639bool XMLUtil::ToFloat( const char* str, float* value )
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
642 return true;
643 }
644 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700645}
646
Lee Thomason51c12712016-06-04 20:18:49 -0700647
Lee Thomason21be8822012-07-15 17:27:22 -0700648bool XMLUtil::ToDouble( const char* str, double* value )
649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
651 return true;
652 }
653 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700654}
655
656
Lee Thomason51c12712016-06-04 20:18:49 -0700657bool XMLUtil::ToInt64(const char* str, int64_t* value)
658{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700659 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
660 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
orbitcowboy710a3322019-05-16 15:30:47 +0200661 *value = static_cast<int64_t>(v);
Lee Thomason51c12712016-06-04 20:18:49 -0700662 return true;
663 }
664 return false;
665}
666
667
cugone75a5acc2019-04-11 22:03:43 -0500668bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
669 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
670 if(TIXML_SSCANF(str, "%llu", &v) == 1) {
671 *value = (uint64_t)v;
672 return true;
673 }
674 return false;
675}
676
677
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700678char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800679{
Dmitry-Me02384662015-03-03 16:02:13 +0300680 TIXMLASSERT( node );
681 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400682 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000683 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000684 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300685 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300686 *node = 0;
687 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 return p;
689 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Dmitry-Me962083b2015-05-26 11:38:30 +0300691 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 static const char* xmlHeader = { "<?" };
693 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300695 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 static const int xmlHeaderLen = 2;
699 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300701 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
705 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400706 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += xmlHeaderLen;
711 }
712 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p += commentHeaderLen;
716 }
717 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300718 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000720 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 p += cdataHeaderLen;
722 text->SetCData( true );
723 }
724 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300725 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000726 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 p += dtdHeaderLen;
728 }
729 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300730 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000731 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 p += elementHeaderLen;
733 }
734 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300735 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000736 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000738 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740
Dmitry-Me02384662015-03-03 16:02:13 +0300741 TIXMLASSERT( returnNode );
742 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 *node = returnNode;
744 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745}
746
747
Lee Thomason751da522012-02-10 08:50:51 -0800748bool XMLDocument::Accept( XMLVisitor* visitor ) const
749{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300750 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 if ( visitor->VisitEnter( *this ) ) {
752 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
753 if ( !node->Accept( visitor ) ) {
754 break;
755 }
756 }
757 }
758 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800759}
Lee Thomason56bdd022012-02-09 18:16:58 -0800760
761
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800762// --------- XMLNode ----------- //
763
764XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 _document( doc ),
766 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200767 _value(),
kezenatorec694152016-11-26 17:21:43 +1000768 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200770 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700771 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200772 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800773{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800774}
775
776
777XMLNode::~XMLNode()
778{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( _parent ) {
781 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800783}
784
Gumichan010f1fa6d2018-02-01 14:16:24 +0100785const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200786{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300787 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530788 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530789 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200790 return _value.GetStr();
791}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800792
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793void XMLNode::SetValue( const char* str, bool staticMem )
794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 }
798 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800801}
802
Dmitry-Me3f63f212017-06-19 18:25:19 +0300803XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700804{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300805 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700806 if (!clone) return 0;
807
808 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300809 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700810 TIXMLASSERT(childClone);
811 clone->InsertEndChild(childClone);
812 }
813 return clone;
814}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800815
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800816void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800817{
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300819 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300820 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800823}
824
825
826void XMLNode::Unlink( XMLNode* child )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300830 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 if ( child == _firstChild ) {
832 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 if ( child == _lastChild ) {
835 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
Lee Thomasond923c672012-01-23 08:44:25 -0800837
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 if ( child->_prev ) {
839 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 if ( child->_next ) {
842 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
Lee Thomason8a763612017-06-16 09:30:16 -0700844 child->_next = 0;
845 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700846 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800847}
848
849
U-Stream\Leeae25a442012-02-17 17:48:16 -0800850void XMLNode::DeleteChild( XMLNode* node )
851{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300852 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100855 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700856 TIXMLASSERT(node->_prev == 0);
857 TIXMLASSERT(node->_next == 0);
858 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400859 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800860}
861
862
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800863XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
864{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300865 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300866 if ( addThis->_document != _document ) {
867 TIXMLASSERT( false );
868 return 0;
869 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800870 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( _lastChild ) {
873 TIXMLASSERT( _firstChild );
874 TIXMLASSERT( _lastChild->_next == 0 );
875 _lastChild->_next = addThis;
876 addThis->_prev = _lastChild;
877 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 TIXMLASSERT( _firstChild == 0 );
883 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800884
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 addThis->_prev = 0;
886 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800890}
891
892
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
894{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300895 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300896 if ( addThis->_document != _document ) {
897 TIXMLASSERT( false );
898 return 0;
899 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800900 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700901
Lee Thomason624d43f2012-10-12 10:58:48 -0700902 if ( _firstChild ) {
903 TIXMLASSERT( _lastChild );
904 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 _firstChild->_prev = addThis;
907 addThis->_next = _firstChild;
908 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800909
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700913 TIXMLASSERT( _lastChild == 0 );
914 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800915
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 addThis->_prev = 0;
917 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400920 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800921}
922
923
924XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
925{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300926 TIXMLASSERT( addThis );
927 if ( addThis->_document != _document ) {
928 TIXMLASSERT( false );
929 return 0;
930 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700931
Dmitry-Meabb2d042014-12-09 12:59:31 +0300932 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300935 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 return 0;
937 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300938 if ( afterThis == addThis ) {
939 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
940 // Now AddThis must disappear from it's location and then
941 // reappear between BeforeThis and OneAfterAddThis.
942 // So just leave it where it is.
943 return addThis;
944 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800945
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // The last node or the only node.
948 return InsertEndChild( addThis );
949 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800950 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 addThis->_prev = afterThis;
952 addThis->_next = afterThis->_next;
953 afterThis->_next->_prev = addThis;
954 afterThis->_next = addThis;
955 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800957}
958
959
960
961
Dmitry-Me886ad972015-07-22 11:00:51 +0300962const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800963{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300964 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300965 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 }
970 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800971}
972
973
Dmitry-Me886ad972015-07-22 11:00:51 +0300974const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800975{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300976 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300977 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300979 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 }
982 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800983}
984
985
Dmitry-Me886ad972015-07-22 11:00:51 +0300986const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300988 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300989 const XMLElement* element = node->ToElementWithName( name );
990 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400991 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
993 }
994 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995}
996
997
Dmitry-Me886ad972015-07-22 11:00:51 +0300998const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999{
Dmitry-Me2667aab2015-04-03 10:56:59 +03001000 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +03001001 const XMLElement* element = node->ToElementWithName( name );
1002 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 }
1006 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001010char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 // This is a recursive method, but thinking about it "at the current level"
1013 // it is a pretty simple flat list:
1014 // <foo/>
1015 // <!-- comment -->
1016 //
1017 // With a special case:
1018 // <foo>
1019 // </foo>
1020 // <!-- comment -->
1021 //
1022 // Where the closing element (/foo) *must* be the next thing after the opening
1023 // element, and the names must match. BUT the tricky bit is that the closing
1024 // element will be read by the child.
1025 //
1026 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1027 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001028
Lee Thomasond946dda2018-04-05 09:11:08 -07001029 XMLDocument::DepthTracker tracker(_document);
1030 if (_document->Error())
1031 return 0;
1032
1033 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001037 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001038 if ( node == 0 ) {
1039 break;
1040 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041
orbitcowboy0e7f2892019-01-15 11:28:49 +01001042 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001043
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001045 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001047 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001049 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 break;
1052 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053
orbitcowboy0e7f2892019-01-15 11:28:49 +01001054 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301055 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001056 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001057 //
1058 // Multiple declarations are allowed but all declarations
1059 // must occur before anything else.
1060 //
1061 // Optimized due to a security test case. If the first node is
1062 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001063 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001064 bool wellLocated = false;
1065
1066 if (ToDocument()) {
1067 if (FirstChild()) {
1068 wellLocated =
1069 FirstChild() &&
1070 FirstChild()->ToDeclaration() &&
1071 LastChild() &&
1072 LastChild()->ToDeclaration();
1073 }
1074 else {
1075 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301076 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001077 }
1078 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001079 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001080 DeleteNode( node );
1081 break;
1082 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301083 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301084
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001085 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001087 // We read the end tag. Return it to the parent.
1088 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001089 if ( parentEndTag ) {
1090 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001091 }
1092 node->_memPool->SetTracked(); // created and then immediately deleted.
1093 DeleteNode( node );
1094 return p;
1095 }
1096
1097 // Handle an end tag returned to this level.
1098 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001099 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001100 if ( endTag.Empty() ) {
1101 if ( ele->ClosingType() == XMLElement::OPEN ) {
1102 mismatch = true;
1103 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001105 else {
1106 if ( ele->ClosingType() != XMLElement::OPEN ) {
1107 mismatch = true;
1108 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001109 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001110 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001113 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001114 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001115 DeleteNode( node );
1116 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001117 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 }
JayXondbfdd8f2014-12-12 20:07:14 -05001119 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001122}
1123
Lee Thomason816d3fa2017-06-05 14:35:55 -07001124/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001125{
1126 if ( node == 0 ) {
1127 return;
1128 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001129 TIXMLASSERT(node->_document);
1130 if (!node->ToDocument()) {
1131 node->_document->MarkInUse(node);
1132 }
1133
Dmitry-Mee3225b12014-09-03 11:03:11 +04001134 MemPool* pool = node->_memPool;
1135 node->~XMLNode();
1136 pool->Free( node );
1137}
1138
Lee Thomason3cebdc42015-01-05 17:16:28 -08001139void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001140{
1141 TIXMLASSERT( insertThis );
1142 TIXMLASSERT( insertThis->_document == _document );
1143
Lee Thomason816d3fa2017-06-05 14:35:55 -07001144 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001145 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001146 }
1147 else {
1148 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001149 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001150 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001151}
1152
Dmitry-Meecb9b072016-10-12 16:44:59 +03001153const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1154{
1155 const XMLElement* element = this->ToElement();
1156 if ( element == 0 ) {
1157 return 0;
1158 }
1159 if ( name == 0 ) {
1160 return element;
1161 }
1162 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1163 return element;
1164 }
1165 return 0;
1166}
1167
Lee Thomason5492a1c2012-01-23 15:32:10 -08001168// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001169char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001172 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001174 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
1176 return p;
1177 }
1178 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1180 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001181 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001183
kezenator4f756162016-11-29 19:46:27 +10001184 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( p && *p ) {
1186 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001187 }
1188 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001189 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 }
1191 }
1192 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001193}
1194
1195
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001196XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 }
1201 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1202 text->SetCData( this->CData() );
1203 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001204}
1205
1206
1207bool XMLText::ShallowEqual( const XMLNode* compare ) const
1208{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001209 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001210 const XMLText* text = compare->ToText();
1211 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212}
1213
1214
Lee Thomason56bdd022012-02-09 18:16:58 -08001215bool XMLText::Accept( XMLVisitor* visitor ) const
1216{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001217 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001219}
1220
1221
Lee Thomason3f57d272012-01-11 15:30:03 -08001222// --------- XMLComment ---------- //
1223
Lee Thomasone4422302012-01-20 17:59:50 -08001224XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001225{
1226}
1227
1228
Lee Thomasonce0763e2012-01-11 15:43:54 -08001229XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001230{
Lee Thomason3f57d272012-01-11 15:30:03 -08001231}
1232
1233
kezenator4f756162016-11-29 19:46:27 +10001234char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001237 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001239 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 }
1241 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001242}
1243
1244
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 }
1250 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1251 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252}
1253
1254
1255bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001258 const XMLComment* comment = compare->ToComment();
1259 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260}
1261
1262
Lee Thomason751da522012-02-10 08:50:51 -08001263bool XMLComment::Accept( XMLVisitor* visitor ) const
1264{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001265 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001267}
Lee Thomason56bdd022012-02-09 18:16:58 -08001268
1269
Lee Thomason50f97b22012-02-11 16:33:40 -08001270// --------- XMLDeclaration ---------- //
1271
1272XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1273{
1274}
1275
1276
1277XMLDeclaration::~XMLDeclaration()
1278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001280}
1281
1282
kezenator4f756162016-11-29 19:46:27 +10001283char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001286 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001288 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 }
1290 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001291}
1292
1293
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001294XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
1299 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1300 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001301}
1302
1303
1304bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1305{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001306 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001307 const XMLDeclaration* declaration = compare->ToDeclaration();
1308 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001309}
1310
1311
1312
Lee Thomason50f97b22012-02-11 16:33:40 -08001313bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1314{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001315 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001317}
1318
1319// --------- XMLUnknown ---------- //
1320
1321XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1322{
1323}
1324
1325
1326XMLUnknown::~XMLUnknown()
1327{
1328}
1329
1330
kezenator4f756162016-11-29 19:46:27 +10001331char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001334 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001336 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 }
1338 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001339}
1340
1341
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001342XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001345 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1348 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001349}
1350
1351
1352bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1353{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001354 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001355 const XMLUnknown* unknown = compare->ToUnknown();
1356 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001357}
1358
1359
Lee Thomason50f97b22012-02-11 16:33:40 -08001360bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1361{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001362 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001364}
1365
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001366// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001367
Gumichan010f1fa6d2018-02-01 14:16:24 +01001368const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001369{
1370 return _name.GetStr();
1371}
1372
Gumichan010f1fa6d2018-02-01 14:16:24 +01001373const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001374{
1375 return _value.GetStr();
1376}
1377
kezenator4f756162016-11-29 19:46:27 +10001378char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001381 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( !p || !*p ) {
1383 return 0;
1384 }
Lee Thomason22aead12012-01-23 13:29:35 -08001385
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001387 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001388 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 return 0;
1390 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001391
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001393 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( *p != '\"' && *p != '\'' ) {
1395 return 0;
1396 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001397
orbitcowboy0e7f2892019-01-15 11:28:49 +01001398 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001400
kezenator4f756162016-11-29 19:46:27 +10001401 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001403}
1404
1405
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001406void XMLAttribute::SetName( const char* n )
1407{
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001409}
1410
1411
Lee Thomason2fa81722012-11-09 12:37:46 -08001412XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001415 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418}
1419
1420
Lee Thomason2fa81722012-11-09 12:37:46 -08001421XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001424 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
1426 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001427}
1428
1429
Lee Thomason51c12712016-06-04 20:18:49 -07001430XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1431{
1432 if (XMLUtil::ToInt64(Value(), value)) {
1433 return XML_SUCCESS;
1434 }
1435 return XML_WRONG_ATTRIBUTE_TYPE;
1436}
1437
1438
cugone75a5acc2019-04-11 22:03:43 -05001439XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1440{
1441 if(XMLUtil::ToUnsigned64(Value(), value)) {
1442 return XML_SUCCESS;
1443 }
1444 return XML_WRONG_ATTRIBUTE_TYPE;
1445}
1446
1447
Lee Thomason2fa81722012-11-09 12:37:46 -08001448XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001451 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001454}
1455
1456
Lee Thomason2fa81722012-11-09 12:37:46 -08001457XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001460 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001463}
1464
1465
Lee Thomason2fa81722012-11-09 12:37:46 -08001466XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001469 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
1471 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001472}
1473
1474
1475void XMLAttribute::SetAttribute( const char* v )
1476{
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001478}
1479
1480
Lee Thomason1ff38e02012-02-14 18:18:16 -08001481void XMLAttribute::SetAttribute( int v )
1482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 char buf[BUF_SIZE];
1484 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001486}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487
1488
1489void XMLAttribute::SetAttribute( unsigned v )
1490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 char buf[BUF_SIZE];
1492 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
1496
Lee Thomason51c12712016-06-04 20:18:49 -07001497void XMLAttribute::SetAttribute(int64_t v)
1498{
1499 char buf[BUF_SIZE];
1500 XMLUtil::ToStr(v, buf, BUF_SIZE);
1501 _value.SetStr(buf);
1502}
1503
Lee Thomasoneffdf952019-08-10 17:49:42 -07001504void XMLAttribute::SetAttribute(uint64_t v)
1505{
1506 char buf[BUF_SIZE];
1507 XMLUtil::ToStr(v, buf, BUF_SIZE);
1508 _value.SetStr(buf);
1509}
Lee Thomason51c12712016-06-04 20:18:49 -07001510
1511
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001512void XMLAttribute::SetAttribute( bool v )
1513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 char buf[BUF_SIZE];
1515 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001517}
1518
1519void XMLAttribute::SetAttribute( double v )
1520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 char buf[BUF_SIZE];
1522 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001524}
1525
1526void XMLAttribute::SetAttribute( float v )
1527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 char buf[BUF_SIZE];
1529 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001531}
1532
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001533
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001534// --------- XMLElement ---------- //
1535XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001536 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001538{
1539}
1540
1541
1542XMLElement::~XMLElement()
1543{
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 while( _rootAttribute ) {
1545 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001546 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001549}
1550
1551
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001552const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1553{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001554 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1556 return a;
1557 }
1558 }
1559 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001560}
1561
1562
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001563const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 const XMLAttribute* a = FindAttribute( name );
1566 if ( !a ) {
1567 return 0;
1568 }
1569 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1570 return a->Value();
1571 }
1572 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001573}
1574
Gumichan010f1fa6d2018-02-01 14:16:24 +01001575int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001576{
1577 int i = defaultValue;
1578 QueryIntAttribute(name, &i);
1579 return i;
1580}
1581
Gumichan010f1fa6d2018-02-01 14:16:24 +01001582unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001583{
1584 unsigned i = defaultValue;
1585 QueryUnsignedAttribute(name, &i);
1586 return i;
1587}
1588
Gumichan010f1fa6d2018-02-01 14:16:24 +01001589int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001590{
1591 int64_t i = defaultValue;
1592 QueryInt64Attribute(name, &i);
1593 return i;
1594}
1595
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01001596uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1597{
1598 uint64_t i = defaultValue;
1599 QueryUnsigned64Attribute(name, &i);
1600 return i;
1601}
1602
Gumichan010f1fa6d2018-02-01 14:16:24 +01001603bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001604{
1605 bool b = defaultValue;
1606 QueryBoolAttribute(name, &b);
1607 return b;
1608}
1609
Gumichan010f1fa6d2018-02-01 14:16:24 +01001610double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001611{
1612 double d = defaultValue;
1613 QueryDoubleAttribute(name, &d);
1614 return d;
1615}
1616
Gumichan010f1fa6d2018-02-01 14:16:24 +01001617float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001618{
1619 float f = defaultValue;
1620 QueryFloatAttribute(name, &f);
1621 return f;
1622}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001623
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001624const char* XMLElement::GetText() const
1625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001627 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 }
1629 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001630}
1631
1632
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001633void XMLElement::SetText( const char* inText )
1634{
Uli Kusterer869bb592014-01-21 01:36:16 +01001635 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001636 FirstChild()->SetValue( inText );
1637 else {
1638 XMLText* theText = GetDocument()->NewText( inText );
1639 InsertFirstChild( theText );
1640 }
1641}
1642
Lee Thomason5bb2d802014-01-24 10:42:57 -08001643
Gumichan010f1fa6d2018-02-01 14:16:24 +01001644void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001645{
1646 char buf[BUF_SIZE];
1647 XMLUtil::ToStr( v, buf, BUF_SIZE );
1648 SetText( buf );
1649}
1650
1651
Gumichan010f1fa6d2018-02-01 14:16:24 +01001652void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001653{
1654 char buf[BUF_SIZE];
1655 XMLUtil::ToStr( v, buf, BUF_SIZE );
1656 SetText( buf );
1657}
1658
1659
Lee Thomason51c12712016-06-04 20:18:49 -07001660void XMLElement::SetText(int64_t v)
1661{
1662 char buf[BUF_SIZE];
1663 XMLUtil::ToStr(v, buf, BUF_SIZE);
1664 SetText(buf);
1665}
1666
cugone47e229e2019-04-12 17:27:28 -05001667void XMLElement::SetText(uint64_t v) {
1668 char buf[BUF_SIZE];
1669 XMLUtil::ToStr(v, buf, BUF_SIZE);
1670 SetText(buf);
1671}
1672
Lee Thomason51c12712016-06-04 20:18:49 -07001673
1674void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001675{
1676 char buf[BUF_SIZE];
1677 XMLUtil::ToStr( v, buf, BUF_SIZE );
1678 SetText( buf );
1679}
1680
1681
Gumichan010f1fa6d2018-02-01 14:16:24 +01001682void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001683{
1684 char buf[BUF_SIZE];
1685 XMLUtil::ToStr( v, buf, BUF_SIZE );
1686 SetText( buf );
1687}
1688
1689
Gumichan010f1fa6d2018-02-01 14:16:24 +01001690void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001691{
1692 char buf[BUF_SIZE];
1693 XMLUtil::ToStr( v, buf, BUF_SIZE );
1694 SetText( buf );
1695}
1696
1697
MortenMacFly4ee49f12013-01-14 20:03:14 +01001698XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001699{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001701 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001702 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 return XML_SUCCESS;
1704 }
1705 return XML_CAN_NOT_CONVERT_TEXT;
1706 }
1707 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001708}
1709
1710
MortenMacFly4ee49f12013-01-14 20:03:14 +01001711XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001714 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001715 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 return XML_SUCCESS;
1717 }
1718 return XML_CAN_NOT_CONVERT_TEXT;
1719 }
1720 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001721}
1722
1723
Lee Thomason51c12712016-06-04 20:18:49 -07001724XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1725{
1726 if (FirstChild() && FirstChild()->ToText()) {
1727 const char* t = FirstChild()->Value();
1728 if (XMLUtil::ToInt64(t, ival)) {
1729 return XML_SUCCESS;
1730 }
1731 return XML_CAN_NOT_CONVERT_TEXT;
1732 }
1733 return XML_NO_TEXT_NODE;
1734}
1735
1736
cugone1dbfe312019-04-12 17:33:49 -05001737XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const
1738{
cugone47e229e2019-04-12 17:27:28 -05001739 if(FirstChild() && FirstChild()->ToText()) {
1740 const char* t = FirstChild()->Value();
1741 if(XMLUtil::ToUnsigned64(t, ival)) {
1742 return XML_SUCCESS;
1743 }
1744 return XML_CAN_NOT_CONVERT_TEXT;
1745 }
1746 return XML_NO_TEXT_NODE;
1747}
1748
1749
MortenMacFly4ee49f12013-01-14 20:03:14 +01001750XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001753 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001754 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 return XML_SUCCESS;
1756 }
1757 return XML_CAN_NOT_CONVERT_TEXT;
1758 }
1759 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001760}
1761
1762
MortenMacFly4ee49f12013-01-14 20:03:14 +01001763XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001764{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001766 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001767 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 return XML_SUCCESS;
1769 }
1770 return XML_CAN_NOT_CONVERT_TEXT;
1771 }
1772 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001773}
1774
1775
MortenMacFly4ee49f12013-01-14 20:03:14 +01001776XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001777{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001779 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001780 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 return XML_SUCCESS;
1782 }
1783 return XML_CAN_NOT_CONVERT_TEXT;
1784 }
1785 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001786}
1787
Josh Wittnercf3dd092016-10-11 18:57:17 -07001788int XMLElement::IntText(int defaultValue) const
1789{
1790 int i = defaultValue;
1791 QueryIntText(&i);
1792 return i;
1793}
1794
1795unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1796{
1797 unsigned i = defaultValue;
1798 QueryUnsignedText(&i);
1799 return i;
1800}
1801
1802int64_t XMLElement::Int64Text(int64_t defaultValue) const
1803{
1804 int64_t i = defaultValue;
1805 QueryInt64Text(&i);
1806 return i;
1807}
1808
cugone1dbfe312019-04-12 17:33:49 -05001809uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1810{
1811 uint64_t i = defaultValue;
1812 QueryUnsigned64Text(&i);
1813 return i;
1814}
1815
Josh Wittnercf3dd092016-10-11 18:57:17 -07001816bool XMLElement::BoolText(bool defaultValue) const
1817{
1818 bool b = defaultValue;
1819 QueryBoolText(&b);
1820 return b;
1821}
1822
1823double XMLElement::DoubleText(double defaultValue) const
1824{
1825 double d = defaultValue;
1826 QueryDoubleText(&d);
1827 return d;
1828}
1829
1830float XMLElement::FloatText(float defaultValue) const
1831{
1832 float f = defaultValue;
1833 QueryFloatText(&f);
1834 return f;
1835}
Lee Thomason21be8822012-07-15 17:27:22 -07001836
1837
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001838XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1839{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 XMLAttribute* last = 0;
1841 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1846 break;
1847 }
1848 }
1849 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001850 attrib = CreateAttribute();
1851 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001853 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 }
1856 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001857 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
1860 attrib->SetName( name );
1861 }
1862 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001863}
1864
1865
U-Stream\Leeae25a442012-02-17 17:48:16 -08001866void XMLElement::DeleteAttribute( const char* name )
1867{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1871 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
1874 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001877 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 break;
1879 }
1880 prev = a;
1881 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001882}
1883
1884
kezenator4f756162016-11-29 19:46:27 +10001885char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001886{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001888
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 // Read the attributes.
1890 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001892 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001893 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 return 0;
1895 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001896
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001898 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001899 XMLAttribute* attrib = CreateAttribute();
1900 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001901 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001902
orbitcowboy0e7f2892019-01-15 11:28:49 +01001903 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001904
kezenator4f756162016-11-29 19:46:27 +10001905 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001907 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001908 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return 0;
1910 }
1911 // There is a minor bug here: if the attribute in the source xml
1912 // document is duplicated, it will not be detected and the
1913 // attribute will be doubly added. However, tracking the 'prevAttribute'
1914 // avoids re-scanning the attribute list. Preferring performance for
1915 // now, may reconsider in the future.
1916 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001917 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
1920 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001921 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 prevAttribute = attrib;
1925 }
1926 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 else if ( *p == '>' ) {
1928 ++p;
1929 break;
1930 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001931 // end of the tag
1932 else if ( *p == '/' && *(p+1) == '>' ) {
1933 _closingType = CLOSED;
1934 return p+2; // done; sealed element.
1935 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001937 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 return 0;
1939 }
1940 }
1941 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001942}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001943
Dmitry-Mee3225b12014-09-03 11:03:11 +04001944void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1945{
1946 if ( attribute == 0 ) {
1947 return;
1948 }
1949 MemPool* pool = attribute->_memPool;
1950 attribute->~XMLAttribute();
1951 pool->Free( attribute );
1952}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001953
Dmitry-Mea60caa22016-11-22 18:28:08 +03001954XMLAttribute* XMLElement::CreateAttribute()
1955{
1956 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1957 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001958 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001959 attrib->_memPool = &_document->_attributePool;
1960 attrib->_memPool->SetTracked();
1961 return attrib;
1962}
1963
ngc92e6202452019-12-03 16:25:53 +01001964
1965XMLElement* XMLElement::PushNewChildElement(const char* name)
1966{
1967 XMLElement* element = _document->NewElement(name);
1968 // by construction, the new element has the same Document, so this
1969 // call will always succeed
1970 InsertEndChild(element);
1971 return element;
1972}
1973
1974XMLComment* XMLElement::PushNewChildComment(const char* comment)
1975{
1976 XMLComment* element = _document->NewComment(comment);
1977 InsertEndChild(element);
1978 return element;
1979}
1980
1981XMLText* XMLElement::PushNewChildText(const char* text)
1982{
1983 XMLText* element = _document->NewText(text);
1984 InsertEndChild(element);
1985 return element;
1986}
1987
1988XMLDeclaration* XMLElement::PushNewChildDeclaration(const char* text)
1989{
1990 XMLDeclaration* element = _document->NewDeclaration(text);
1991 InsertEndChild(element);
1992 return element;
1993}
1994
1995XMLUnknown* XMLElement::PushNewUnknown(const char* text)
1996{
1997 XMLUnknown* element = _document->NewUnknown(text);
1998 InsertEndChild(element);
1999 return element;
2000}
2001
2002
2003
Lee Thomason67d61312012-01-24 16:01:51 -08002004//
2005// <ele></ele>
2006// <ele>foo<b>bar</b></ele>
2007//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002008char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08002009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10002011 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08002012
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 // The closing element is the </element> form. It is
2014 // parsed just like a regular element then deleted from
2015 // the DOM.
2016 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 ++p;
2019 }
Lee Thomason67d61312012-01-24 16:01:51 -08002020
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 p = _value.ParseName( p );
2022 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 return 0;
2024 }
Lee Thomason67d61312012-01-24 16:01:51 -08002025
kezenator4f756162016-11-29 19:46:27 +10002026 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03002027 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 return p;
2029 }
Lee Thomason67d61312012-01-24 16:01:51 -08002030
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002031 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08002033}
2034
2035
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002036
2037XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
2042 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
2043 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2044 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
2045 }
2046 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002047}
2048
2049
2050bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2051{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002052 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03002054 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002055
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 const XMLAttribute* a=FirstAttribute();
2057 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002058
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 while ( a && b ) {
2060 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2061 return false;
2062 }
2063 a = a->Next();
2064 b = b->Next();
2065 }
2066 if ( a || b ) {
2067 // different count
2068 return false;
2069 }
2070 return true;
2071 }
2072 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002073}
2074
2075
Lee Thomason751da522012-02-10 08:50:51 -08002076bool XMLElement::Accept( XMLVisitor* visitor ) const
2077{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002078 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2081 if ( !node->Accept( visitor ) ) {
2082 break;
2083 }
2084 }
2085 }
2086 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08002087}
Lee Thomason56bdd022012-02-09 18:16:58 -08002088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002089
Lee Thomason3f57d272012-01-11 15:30:03 -08002090// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002091
2092// Warning: List must match 'enum XMLError'
2093const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2094 "XML_SUCCESS",
2095 "XML_NO_ATTRIBUTE",
2096 "XML_WRONG_ATTRIBUTE_TYPE",
2097 "XML_ERROR_FILE_NOT_FOUND",
2098 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2099 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002100 "XML_ERROR_PARSING_ELEMENT",
2101 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002102 "XML_ERROR_PARSING_TEXT",
2103 "XML_ERROR_PARSING_CDATA",
2104 "XML_ERROR_PARSING_COMMENT",
2105 "XML_ERROR_PARSING_DECLARATION",
2106 "XML_ERROR_PARSING_UNKNOWN",
2107 "XML_ERROR_EMPTY_DOCUMENT",
2108 "XML_ERROR_MISMATCHED_ELEMENT",
2109 "XML_ERROR_PARSING",
2110 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002111 "XML_NO_TEXT_NODE",
2112 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002113};
2114
2115
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002116XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 _writeBOM( false ),
2119 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002120 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002121 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002122 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002123 _errorLineNum( 0 ),
2124 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002125 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002126 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002127 _unlinked(),
2128 _elementPool(),
2129 _attributePool(),
2130 _textPool(),
2131 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002132{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002133 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2134 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002135}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002136
2137
Lee Thomason3f57d272012-01-11 15:30:03 -08002138XMLDocument::~XMLDocument()
2139{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002140 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002141}
2142
2143
orbitcowboy73f54092019-08-14 09:30:30 +02002144void XMLDocument::MarkInUse(const XMLNode* const node)
Lee Thomason816d3fa2017-06-05 14:35:55 -07002145{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002146 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002147 TIXMLASSERT(node->_parent == 0);
2148
2149 for (int i = 0; i < _unlinked.Size(); ++i) {
2150 if (node == _unlinked[i]) {
2151 _unlinked.SwapRemove(i);
2152 break;
2153 }
2154 }
2155}
2156
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002157void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002158{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002159 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002160 while( _unlinked.Size()) {
2161 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2162 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002163
Peter Matula50689912018-01-09 12:52:26 +01002164#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002165 const bool hadError = Error();
2166#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002167 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002168
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 delete [] _charBuffer;
2170 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002171 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002172
2173#if 0
2174 _textPool.Trace( "text" );
2175 _elementPool.Trace( "element" );
2176 _commentPool.Trace( "comment" );
2177 _attributePool.Trace( "attribute" );
2178#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002179
Peter Matula50689912018-01-09 12:52:26 +01002180#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002181 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002182 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2183 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2184 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2185 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2186 }
2187#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002188}
2189
Lee Thomason3f57d272012-01-11 15:30:03 -08002190
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002191void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002192{
2193 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002194 if (target == this) {
2195 return; // technically success - a no-op.
2196 }
Lee Thomason7085f002017-06-01 18:09:43 -07002197
2198 target->Clear();
2199 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2200 target->InsertEndChild(node->DeepClone(target));
2201 }
2202}
2203
Lee Thomason2c85a712012-01-31 08:24:24 -08002204XMLElement* XMLDocument::NewElement( const char* name )
2205{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002206 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 ele->SetName( name );
2208 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002209}
2210
2211
Lee Thomason1ff38e02012-02-14 18:18:16 -08002212XMLComment* XMLDocument::NewComment( const char* str )
2213{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002214 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 comment->SetValue( str );
2216 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002217}
2218
2219
2220XMLText* XMLDocument::NewText( const char* str )
2221{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002222 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 text->SetValue( str );
2224 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002225}
2226
2227
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002228XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2229{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002230 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2232 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002233}
2234
2235
2236XMLUnknown* XMLDocument::NewUnknown( const char* str )
2237{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002238 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 unk->SetValue( str );
2240 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002241}
2242
Dmitry-Me01578db2014-08-19 10:18:48 +04002243static FILE* callfopen( const char* filepath, const char* mode )
2244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002245 TIXMLASSERT( filepath );
2246 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002247#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2248 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002249 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002250 if ( err ) {
2251 return 0;
2252 }
2253#else
2254 FILE* fp = fopen( filepath, mode );
2255#endif
2256 return fp;
2257}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002258
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002259void XMLDocument::DeleteNode( XMLNode* node ) {
2260 TIXMLASSERT( node );
2261 TIXMLASSERT(node->_document == this );
2262 if (node->_parent) {
2263 node->_parent->DeleteChild( node );
2264 }
2265 else {
2266 // Isn't in the tree.
2267 // Use the parent delete.
2268 // Also, we need to mark it tracked: we 'know'
2269 // it was never used.
2270 node->_memPool->SetTracked();
2271 // Call the static XMLNode version:
2272 XMLNode::DeleteNode(node);
2273 }
2274}
2275
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002276
Lee Thomason2fa81722012-11-09 12:37:46 -08002277XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002278{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002279 if ( !filename ) {
2280 TIXMLASSERT( false );
2281 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2282 return _errorID;
2283 }
2284
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002285 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002286 FILE* fp = callfopen( filename, "rb" );
2287 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002288 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 }
2291 LoadFile( fp );
2292 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002293 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294}
2295
Dmitry-Me901fed52015-09-25 10:29:51 +03002296// This is likely overengineered template art to have a check that unsigned long value incremented
2297// by one still fits into size_t. If size_t type is larger than unsigned long type
2298// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2299// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2300// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2301// types sizes relate to each other.
2302template
2303<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2304struct LongFitsIntoSizeTMinusOne {
2305 static bool Fits( unsigned long value )
2306 {
orbitcowboy710a3322019-05-16 15:30:47 +02002307 return value < static_cast<size_t>(-1);
Dmitry-Me901fed52015-09-25 10:29:51 +03002308 }
2309};
2310
2311template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002312struct LongFitsIntoSizeTMinusOne<false> {
2313 static bool Fits( unsigned long )
2314 {
2315 return true;
2316 }
2317};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002318
Lee Thomason2fa81722012-11-09 12:37:46 -08002319XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002320{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002321 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002323 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002324 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002325 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002326 return _errorID;
2327 }
2328
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002330 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002332 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002333 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002334 return _errorID;
2335 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002336 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002337
Dmitry-Me901fed52015-09-25 10:29:51 +03002338 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002339 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002340 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002341 return _errorID;
2342 }
2343
Dmitry-Me72801b82015-05-07 09:41:39 +03002344 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002345 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002346 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002348
Dmitry-Me72801b82015-05-07 09:41:39 +03002349 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002350 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002352 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002354 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002355 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002357
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002359
Dmitry-Me97476b72015-01-01 16:15:57 +03002360 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002362}
2363
2364
Lee Thomason2fa81722012-11-09 12:37:46 -08002365XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002366{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002367 if ( !filename ) {
2368 TIXMLASSERT( false );
2369 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2370 return _errorID;
2371 }
2372
Dmitry-Me01578db2014-08-19 10:18:48 +04002373 FILE* fp = callfopen( filename, "w" );
2374 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002375 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 }
2378 SaveFile(fp, compact);
2379 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002381}
2382
2383
Lee Thomason2fa81722012-11-09 12:37:46 -08002384XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002385{
Ant Mitchell189198f2015-03-24 16:20:36 +00002386 // Clear any error from the last save, otherwise it will get reported
2387 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002388 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 XMLPrinter stream( fp, compact );
2390 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002391 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002392}
2393
Lee Thomason1ff38e02012-02-14 18:18:16 -08002394
Lee Thomason2fa81722012-11-09 12:37:46 -08002395XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002396{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002397 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002398
Lee Thomason82d32002014-02-21 22:47:18 -08002399 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002400 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002402 }
orbitcowboy710a3322019-05-16 15:30:47 +02002403 if ( len == static_cast<size_t>(-1) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 len = strlen( p );
2405 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002406 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002407 _charBuffer = new char[ len+1 ];
2408 memcpy( _charBuffer, p, len );
2409 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002410
Dmitry-Me97476b72015-01-01 16:15:57 +03002411 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002412 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002413 // clean up now essentially dangling memory.
2414 // and the parse fail can put objects in the
2415 // pools that are dead and inaccessible.
2416 DeleteChildren();
2417 _elementPool.Clear();
2418 _attributePool.Clear();
2419 _textPool.Clear();
2420 _commentPool.Clear();
2421 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002422 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002423}
2424
2425
PKEuS1c5f99e2013-07-06 11:28:39 +02002426void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002427{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002428 if ( streamer ) {
2429 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002431 else {
2432 XMLPrinter stdoutStreamer( stdout );
2433 Accept( &stdoutStreamer );
2434 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002435}
2436
2437
Lee Thomasonaa188392017-09-19 17:54:31 -07002438void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002439{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002440 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002442 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002443 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002444
orbitcowboy0e7f2892019-01-15 11:28:49 +01002445 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002446 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002447
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002448 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002449 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
Lee Thomasonaa188392017-09-19 17:54:31 -07002450
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002451 if (format) {
2452 size_t len = strlen(buffer);
2453 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2454 len = strlen(buffer);
2455
2456 va_list va;
2457 va_start(va, format);
2458 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2459 va_end(va);
2460 }
2461 _errorStr.SetStr(buffer);
2462 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002463}
2464
Lee Thomasonaa188392017-09-19 17:54:31 -07002465
Lee Thomasone90e9012016-12-24 07:34:39 -08002466/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002467{
kezenator5a700712016-11-26 13:54:42 +10002468 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2469 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002470 TIXMLASSERT( errorName && errorName[0] );
2471 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002472}
Lee Thomason5cae8972012-01-24 18:03:07 -08002473
Gumichan010f1fa6d2018-02-01 14:16:24 +01002474const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002475{
Lee Thomasonaa188392017-09-19 17:54:31 -07002476 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002477}
2478
Lee Thomasonf49b9652017-10-11 10:57:49 -07002479
2480void XMLDocument::PrintError() const
2481{
2482 printf("%s\n", ErrorStr());
2483}
2484
kezenator5a700712016-11-26 13:54:42 +10002485const char* XMLDocument::ErrorName() const
2486{
Lee Thomasone90e9012016-12-24 07:34:39 -08002487 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002488}
2489
Dmitry-Me97476b72015-01-01 16:15:57 +03002490void XMLDocument::Parse()
2491{
2492 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2493 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002494 _parseCurLineNum = 1;
2495 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002496 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002497 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002498 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002499 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002500 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002501 return;
2502 }
kezenator4f756162016-11-29 19:46:27 +10002503 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002504}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002505
Lee Thomasonf928c352018-04-05 09:24:20 -07002506void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002507{
2508 _parsingDepth++;
2509 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002510 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002511 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002512}
2513
Lee Thomasonf928c352018-04-05 09:24:20 -07002514void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002515{
2516 TIXMLASSERT(_parsingDepth > 0);
2517 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002518}
2519
PKEuS1bfb9542013-08-04 13:51:17 +02002520XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002521 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002522 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002523 _firstElement( true ),
2524 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002525 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002526 _textDepth( -1 ),
2527 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002528 _compactMode( compact ),
2529 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002532 _entityFlag[i] = false;
2533 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 }
2535 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002536 const char entityValue = entities[i].value;
orbitcowboy710a3322019-05-16 15:30:47 +02002537 const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
Dmitry-Mea28eb072017-08-25 18:34:18 +03002538 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2539 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002540 }
orbitcowboy710a3322019-05-16 15:30:47 +02002541 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2542 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2543 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002544 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002545}
2546
2547
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002548void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002549{
2550 va_list va;
2551 va_start( va, format );
2552
Lee Thomason624d43f2012-10-12 10:58:48 -07002553 if ( _fp ) {
2554 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002555 }
2556 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002557 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 // Close out and re-start the va-args
2559 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002560 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002562 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002563 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002564 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002565 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002566 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002567}
2568
2569
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002570void XMLPrinter::Write( const char* data, size_t size )
2571{
2572 if ( _fp ) {
2573 fwrite ( data , sizeof(char), size, _fp);
2574 }
2575 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002576 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002577 memcpy( p, data, size );
2578 p[size] = 0;
2579 }
2580}
2581
2582
2583void XMLPrinter::Putc( char ch )
2584{
2585 if ( _fp ) {
2586 fputc ( ch, _fp);
2587 }
2588 else {
2589 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2590 p[0] = ch;
2591 p[1] = 0;
2592 }
2593}
2594
2595
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002596void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002597{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002598 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002599 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002600 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002601}
2602
2603
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002604void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002606 // Look for runs of bytes between entities to print.
2607 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002608
Lee Thomason624d43f2012-10-12 10:58:48 -07002609 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002610 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002612 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 // Remember, char is sometimes signed. (How many times has that bitten me?)
2614 if ( *q > 0 && *q < ENTITY_RANGE ) {
2615 // Check for entities. If one is found, flush
2616 // the stream up until the entity, write the
2617 // entity, and keep looking.
orbitcowboy710a3322019-05-16 15:30:47 +02002618 if ( flag[static_cast<unsigned char>(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002620 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002621 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002622 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002623 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002624 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002625 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002626 for( int i=0; i<NUM_ENTITIES; ++i ) {
2627 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002628 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002629 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002630 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002631 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 break;
2633 }
2634 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002635 if ( !entityPatternPrinted ) {
2636 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2637 TIXMLASSERT( false );
2638 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002639 ++p;
2640 }
2641 }
2642 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002643 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 }
Derek Quambe69ae62018-04-18 13:40:46 -05002645 // Flush the remaining string. This will be the entire
2646 // string if an entity wasn't found.
2647 if ( p < q ) {
2648 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002649 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Derek Quambe69ae62018-04-18 13:40:46 -05002650 Write( p, toPrint );
2651 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 }
Derek Quambe69ae62018-04-18 13:40:46 -05002653 else {
2654 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002655 }
Lee Thomason857b8682012-01-25 17:50:25 -08002656}
2657
U-Stream\Leeae25a442012-02-17 17:48:16 -08002658
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002659void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002660{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002661 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002662 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002663 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 }
2665 if ( writeDec ) {
2666 PushDeclaration( "xml version=\"1.0\"" );
2667 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002668}
2669
2670
Uli Kusterer593a33d2014-02-01 12:48:51 +01002671void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002672{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002673 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002674 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002675
Uli Kusterer593a33d2014-02-01 12:48:51 +01002676 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002677 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002678 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002679 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002680
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002681 Write ( "<" );
2682 Write ( name );
2683
Lee Thomason624d43f2012-10-12 10:58:48 -07002684 _elementJustOpened = true;
2685 _firstElement = false;
2686 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002687}
2688
2689
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002690void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002691{
Lee Thomason624d43f2012-10-12 10:58:48 -07002692 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002693 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002694 Write( name );
2695 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002697 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002698}
2699
2700
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002701void XMLPrinter::PushAttribute( const char* name, int v )
2702{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002703 char buf[BUF_SIZE];
2704 XMLUtil::ToStr( v, buf, BUF_SIZE );
2705 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002706}
2707
2708
2709void XMLPrinter::PushAttribute( const char* name, unsigned v )
2710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 char buf[BUF_SIZE];
2712 XMLUtil::ToStr( v, buf, BUF_SIZE );
2713 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002714}
2715
2716
Lee Thomason51c12712016-06-04 20:18:49 -07002717void XMLPrinter::PushAttribute(const char* name, int64_t v)
2718{
2719 char buf[BUF_SIZE];
2720 XMLUtil::ToStr(v, buf, BUF_SIZE);
2721 PushAttribute(name, buf);
2722}
2723
2724
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002725void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2726{
2727 char buf[BUF_SIZE];
2728 XMLUtil::ToStr(v, buf, BUF_SIZE);
2729 PushAttribute(name, buf);
2730}
2731
2732
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002733void XMLPrinter::PushAttribute( const char* name, bool v )
2734{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002735 char buf[BUF_SIZE];
2736 XMLUtil::ToStr( v, buf, BUF_SIZE );
2737 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002738}
2739
2740
2741void XMLPrinter::PushAttribute( const char* name, double v )
2742{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002743 char buf[BUF_SIZE];
2744 XMLUtil::ToStr( v, buf, BUF_SIZE );
2745 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002746}
2747
2748
Uli Kustererca412e82014-02-01 13:35:05 +01002749void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002750{
Lee Thomason624d43f2012-10-12 10:58:48 -07002751 --_depth;
2752 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002753
Lee Thomason624d43f2012-10-12 10:58:48 -07002754 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002755 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002756 }
2757 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002758 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002759 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002760 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002761 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002762 Write ( "</" );
2763 Write ( name );
2764 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002765 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002766
Lee Thomason624d43f2012-10-12 10:58:48 -07002767 if ( _textDepth == _depth ) {
2768 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002769 }
Uli Kustererca412e82014-02-01 13:35:05 +01002770 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002771 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002772 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002773 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002774}
2775
2776
Dmitry-Mea092bc12014-12-23 17:57:05 +03002777void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002778{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002779 if ( !_elementJustOpened ) {
2780 return;
2781 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002782 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002783 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002784}
2785
2786
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002787void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002788{
Lee Thomason624d43f2012-10-12 10:58:48 -07002789 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002790
Dmitry-Mea092bc12014-12-23 17:57:05 +03002791 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002792 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002793 Write( "<![CDATA[" );
2794 Write( text );
2795 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002796 }
2797 else {
2798 PrintString( text, true );
2799 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002800}
2801
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002802
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002803void XMLPrinter::PushText( int64_t value )
2804{
2805 char buf[BUF_SIZE];
2806 XMLUtil::ToStr( value, buf, BUF_SIZE );
2807 PushText( buf, false );
2808}
2809
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002810
2811void XMLPrinter::PushText( uint64_t value )
2812{
2813 char buf[BUF_SIZE];
2814 XMLUtil::ToStr(value, buf, BUF_SIZE);
2815 PushText(buf, false);
2816}
2817
2818
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002819void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002820{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002821 char buf[BUF_SIZE];
2822 XMLUtil::ToStr( value, buf, BUF_SIZE );
2823 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002824}
2825
2826
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002827void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002828{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002829 char buf[BUF_SIZE];
2830 XMLUtil::ToStr( value, buf, BUF_SIZE );
2831 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002832}
2833
2834
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002835void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002836{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002837 char buf[BUF_SIZE];
2838 XMLUtil::ToStr( value, buf, BUF_SIZE );
2839 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002840}
2841
2842
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002843void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002845 char buf[BUF_SIZE];
2846 XMLUtil::ToStr( value, buf, BUF_SIZE );
2847 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002848}
2849
2850
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002851void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002852{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002853 char buf[BUF_SIZE];
2854 XMLUtil::ToStr( value, buf, BUF_SIZE );
2855 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002856}
2857
Lee Thomason5cae8972012-01-24 18:03:07 -08002858
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002859void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002860{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002861 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002862 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002863 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002864 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002865 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002866 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002867
2868 Write( "<!--" );
2869 Write( comment );
2870 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002871}
Lee Thomason751da522012-02-10 08:50:51 -08002872
2873
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002874void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002875{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002876 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002877 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002878 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002879 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002880 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002881 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002882
2883 Write( "<?" );
2884 Write( value );
2885 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002886}
2887
2888
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002889void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002890{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002891 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002892 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002893 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002894 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002895 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002896 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002897
2898 Write( "<!" );
2899 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002900 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002901}
2902
2903
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002904bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002905{
Lee Thomason624d43f2012-10-12 10:58:48 -07002906 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002907 if ( doc.HasBOM() ) {
2908 PushHeader( true, false );
2909 }
2910 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002911}
2912
2913
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002914bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002915{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002916 const XMLElement* parentElem = 0;
2917 if ( element.Parent() ) {
2918 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002919 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002920 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002921 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002922 while ( attribute ) {
2923 PushAttribute( attribute->Name(), attribute->Value() );
2924 attribute = attribute->Next();
2925 }
2926 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002927}
2928
2929
Uli Kustererca412e82014-02-01 13:35:05 +01002930bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002931{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002932 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002933 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002934}
2935
2936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002937bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002939 PushText( text.Value(), text.CData() );
2940 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002941}
2942
2943
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002944bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002945{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002946 PushComment( comment.Value() );
2947 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002948}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002949
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002950bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002952 PushDeclaration( declaration.Value() );
2953 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002954}
2955
2956
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002957bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002958{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002959 PushUnknown( unknown.Value() );
2960 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002961}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002962
Lee Thomason685b8952012-11-12 13:00:06 -08002963} // namespace tinyxml2