blob: df84f776985771dd9bb2418521af29578755f2b4 [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
Lee Thomason67d61312012-01-24 16:01:51 -08001964//
1965// <ele></ele>
1966// <ele>foo<b>bar</b></ele>
1967//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001968char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001971 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001972
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 // The closing element is the </element> form. It is
1974 // parsed just like a regular element then deleted from
1975 // the DOM.
1976 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 ++p;
1979 }
Lee Thomason67d61312012-01-24 16:01:51 -08001980
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 p = _value.ParseName( p );
1982 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 return 0;
1984 }
Lee Thomason67d61312012-01-24 16:01:51 -08001985
kezenator4f756162016-11-29 19:46:27 +10001986 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001987 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 return p;
1989 }
Lee Thomason67d61312012-01-24 16:01:51 -08001990
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001991 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001993}
1994
1995
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001996
1997XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1998{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 }
2002 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
2003 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2004 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
2005 }
2006 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002007}
2008
2009
2010bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2011{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002012 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03002014 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002015
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 const XMLAttribute* a=FirstAttribute();
2017 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002018
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 while ( a && b ) {
2020 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2021 return false;
2022 }
2023 a = a->Next();
2024 b = b->Next();
2025 }
2026 if ( a || b ) {
2027 // different count
2028 return false;
2029 }
2030 return true;
2031 }
2032 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002033}
2034
2035
Lee Thomason751da522012-02-10 08:50:51 -08002036bool XMLElement::Accept( XMLVisitor* visitor ) const
2037{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002038 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2041 if ( !node->Accept( visitor ) ) {
2042 break;
2043 }
2044 }
2045 }
2046 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08002047}
Lee Thomason56bdd022012-02-09 18:16:58 -08002048
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002049
Lee Thomason3f57d272012-01-11 15:30:03 -08002050// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002051
2052// Warning: List must match 'enum XMLError'
2053const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2054 "XML_SUCCESS",
2055 "XML_NO_ATTRIBUTE",
2056 "XML_WRONG_ATTRIBUTE_TYPE",
2057 "XML_ERROR_FILE_NOT_FOUND",
2058 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2059 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002060 "XML_ERROR_PARSING_ELEMENT",
2061 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002062 "XML_ERROR_PARSING_TEXT",
2063 "XML_ERROR_PARSING_CDATA",
2064 "XML_ERROR_PARSING_COMMENT",
2065 "XML_ERROR_PARSING_DECLARATION",
2066 "XML_ERROR_PARSING_UNKNOWN",
2067 "XML_ERROR_EMPTY_DOCUMENT",
2068 "XML_ERROR_MISMATCHED_ELEMENT",
2069 "XML_ERROR_PARSING",
2070 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002071 "XML_NO_TEXT_NODE",
2072 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002073};
2074
2075
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002076XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _writeBOM( false ),
2079 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002080 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002081 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002082 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002083 _errorLineNum( 0 ),
2084 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002085 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002086 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002087 _unlinked(),
2088 _elementPool(),
2089 _attributePool(),
2090 _textPool(),
2091 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002092{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002093 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2094 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002095}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002096
2097
Lee Thomason3f57d272012-01-11 15:30:03 -08002098XMLDocument::~XMLDocument()
2099{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002100 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002101}
2102
2103
orbitcowboy73f54092019-08-14 09:30:30 +02002104void XMLDocument::MarkInUse(const XMLNode* const node)
Lee Thomason816d3fa2017-06-05 14:35:55 -07002105{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002106 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002107 TIXMLASSERT(node->_parent == 0);
2108
2109 for (int i = 0; i < _unlinked.Size(); ++i) {
2110 if (node == _unlinked[i]) {
2111 _unlinked.SwapRemove(i);
2112 break;
2113 }
2114 }
2115}
2116
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002117void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002118{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002119 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002120 while( _unlinked.Size()) {
2121 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2122 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002123
Peter Matula50689912018-01-09 12:52:26 +01002124#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002125 const bool hadError = Error();
2126#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002127 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002128
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 delete [] _charBuffer;
2130 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002131 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002132
2133#if 0
2134 _textPool.Trace( "text" );
2135 _elementPool.Trace( "element" );
2136 _commentPool.Trace( "comment" );
2137 _attributePool.Trace( "attribute" );
2138#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002139
Peter Matula50689912018-01-09 12:52:26 +01002140#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002141 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002142 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2143 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2144 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2145 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2146 }
2147#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002148}
2149
Lee Thomason3f57d272012-01-11 15:30:03 -08002150
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002151void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002152{
2153 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002154 if (target == this) {
2155 return; // technically success - a no-op.
2156 }
Lee Thomason7085f002017-06-01 18:09:43 -07002157
2158 target->Clear();
2159 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2160 target->InsertEndChild(node->DeepClone(target));
2161 }
2162}
2163
Lee Thomason2c85a712012-01-31 08:24:24 -08002164XMLElement* XMLDocument::NewElement( const char* name )
2165{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002166 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 ele->SetName( name );
2168 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002169}
2170
2171
Lee Thomason1ff38e02012-02-14 18:18:16 -08002172XMLComment* XMLDocument::NewComment( const char* str )
2173{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002174 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 comment->SetValue( str );
2176 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002177}
2178
2179
2180XMLText* XMLDocument::NewText( const char* str )
2181{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002182 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 text->SetValue( str );
2184 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002185}
2186
2187
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002188XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2189{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002190 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2192 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002193}
2194
2195
2196XMLUnknown* XMLDocument::NewUnknown( const char* str )
2197{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002198 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 unk->SetValue( str );
2200 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002201}
2202
Dmitry-Me01578db2014-08-19 10:18:48 +04002203static FILE* callfopen( const char* filepath, const char* mode )
2204{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002205 TIXMLASSERT( filepath );
2206 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002207#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2208 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002209 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002210 if ( err ) {
2211 return 0;
2212 }
2213#else
2214 FILE* fp = fopen( filepath, mode );
2215#endif
2216 return fp;
2217}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002218
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002219void XMLDocument::DeleteNode( XMLNode* node ) {
2220 TIXMLASSERT( node );
2221 TIXMLASSERT(node->_document == this );
2222 if (node->_parent) {
2223 node->_parent->DeleteChild( node );
2224 }
2225 else {
2226 // Isn't in the tree.
2227 // Use the parent delete.
2228 // Also, we need to mark it tracked: we 'know'
2229 // it was never used.
2230 node->_memPool->SetTracked();
2231 // Call the static XMLNode version:
2232 XMLNode::DeleteNode(node);
2233 }
2234}
2235
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002236
Lee Thomason2fa81722012-11-09 12:37:46 -08002237XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002239 if ( !filename ) {
2240 TIXMLASSERT( false );
2241 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2242 return _errorID;
2243 }
2244
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002245 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002246 FILE* fp = callfopen( filename, "rb" );
2247 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002248 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 }
2251 LoadFile( fp );
2252 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
Dmitry-Me901fed52015-09-25 10:29:51 +03002256// This is likely overengineered template art to have a check that unsigned long value incremented
2257// by one still fits into size_t. If size_t type is larger than unsigned long type
2258// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2259// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2260// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2261// types sizes relate to each other.
2262template
2263<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2264struct LongFitsIntoSizeTMinusOne {
2265 static bool Fits( unsigned long value )
2266 {
orbitcowboy710a3322019-05-16 15:30:47 +02002267 return value < static_cast<size_t>(-1);
Dmitry-Me901fed52015-09-25 10:29:51 +03002268 }
2269};
2270
2271template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002272struct LongFitsIntoSizeTMinusOne<false> {
2273 static bool Fits( unsigned long )
2274 {
2275 return true;
2276 }
2277};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002278
Lee Thomason2fa81722012-11-09 12:37:46 -08002279XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002280{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002281 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002283 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002284 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002285 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002286 return _errorID;
2287 }
2288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002290 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002292 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002293 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002294 return _errorID;
2295 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002296 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297
Dmitry-Me901fed52015-09-25 10:29:51 +03002298 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002299 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002300 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002301 return _errorID;
2302 }
2303
Dmitry-Me72801b82015-05-07 09:41:39 +03002304 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002305 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002306 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002308
Dmitry-Me72801b82015-05-07 09:41:39 +03002309 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002310 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002312 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002314 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002315 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002317
Lee Thomason624d43f2012-10-12 10:58:48 -07002318 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002319
Dmitry-Me97476b72015-01-01 16:15:57 +03002320 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002321 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322}
2323
2324
Lee Thomason2fa81722012-11-09 12:37:46 -08002325XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002326{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002327 if ( !filename ) {
2328 TIXMLASSERT( false );
2329 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2330 return _errorID;
2331 }
2332
Dmitry-Me01578db2014-08-19 10:18:48 +04002333 FILE* fp = callfopen( filename, "w" );
2334 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002335 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002336 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 }
2338 SaveFile(fp, compact);
2339 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002340 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002341}
2342
2343
Lee Thomason2fa81722012-11-09 12:37:46 -08002344XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002345{
Ant Mitchell189198f2015-03-24 16:20:36 +00002346 // Clear any error from the last save, otherwise it will get reported
2347 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002348 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 XMLPrinter stream( fp, compact );
2350 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002352}
2353
Lee Thomason1ff38e02012-02-14 18:18:16 -08002354
Lee Thomason2fa81722012-11-09 12:37:46 -08002355XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002356{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002357 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002358
Lee Thomason82d32002014-02-21 22:47:18 -08002359 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002360 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 }
orbitcowboy710a3322019-05-16 15:30:47 +02002363 if ( len == static_cast<size_t>(-1) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 len = strlen( p );
2365 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002366 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002367 _charBuffer = new char[ len+1 ];
2368 memcpy( _charBuffer, p, len );
2369 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002370
Dmitry-Me97476b72015-01-01 16:15:57 +03002371 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002372 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002373 // clean up now essentially dangling memory.
2374 // and the parse fail can put objects in the
2375 // pools that are dead and inaccessible.
2376 DeleteChildren();
2377 _elementPool.Clear();
2378 _attributePool.Clear();
2379 _textPool.Clear();
2380 _commentPool.Clear();
2381 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002382 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002383}
2384
2385
PKEuS1c5f99e2013-07-06 11:28:39 +02002386void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002387{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002388 if ( streamer ) {
2389 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002390 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002391 else {
2392 XMLPrinter stdoutStreamer( stdout );
2393 Accept( &stdoutStreamer );
2394 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002395}
2396
2397
Lee Thomasonaa188392017-09-19 17:54:31 -07002398void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002399{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002400 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002402 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002403 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002404
orbitcowboy0e7f2892019-01-15 11:28:49 +01002405 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002406 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002407
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002408 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002409 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 -07002410
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002411 if (format) {
2412 size_t len = strlen(buffer);
2413 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2414 len = strlen(buffer);
2415
2416 va_list va;
2417 va_start(va, format);
2418 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2419 va_end(va);
2420 }
2421 _errorStr.SetStr(buffer);
2422 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002423}
2424
Lee Thomasonaa188392017-09-19 17:54:31 -07002425
Lee Thomasone90e9012016-12-24 07:34:39 -08002426/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002427{
kezenator5a700712016-11-26 13:54:42 +10002428 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2429 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002430 TIXMLASSERT( errorName && errorName[0] );
2431 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002432}
Lee Thomason5cae8972012-01-24 18:03:07 -08002433
Gumichan010f1fa6d2018-02-01 14:16:24 +01002434const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002435{
Lee Thomasonaa188392017-09-19 17:54:31 -07002436 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002437}
2438
Lee Thomasonf49b9652017-10-11 10:57:49 -07002439
2440void XMLDocument::PrintError() const
2441{
2442 printf("%s\n", ErrorStr());
2443}
2444
kezenator5a700712016-11-26 13:54:42 +10002445const char* XMLDocument::ErrorName() const
2446{
Lee Thomasone90e9012016-12-24 07:34:39 -08002447 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002448}
2449
Dmitry-Me97476b72015-01-01 16:15:57 +03002450void XMLDocument::Parse()
2451{
2452 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2453 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002454 _parseCurLineNum = 1;
2455 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002456 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002457 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002458 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002459 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002460 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002461 return;
2462 }
kezenator4f756162016-11-29 19:46:27 +10002463 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002464}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002465
Lee Thomasonf928c352018-04-05 09:24:20 -07002466void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002467{
2468 _parsingDepth++;
2469 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002470 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002471 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002472}
2473
Lee Thomasonf928c352018-04-05 09:24:20 -07002474void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002475{
2476 TIXMLASSERT(_parsingDepth > 0);
2477 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002478}
2479
PKEuS1bfb9542013-08-04 13:51:17 +02002480XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002481 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002482 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002483 _firstElement( true ),
2484 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002485 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002486 _textDepth( -1 ),
2487 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002488 _compactMode( compact ),
2489 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002491 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002492 _entityFlag[i] = false;
2493 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002494 }
2495 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002496 const char entityValue = entities[i].value;
orbitcowboy710a3322019-05-16 15:30:47 +02002497 const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
Dmitry-Mea28eb072017-08-25 18:34:18 +03002498 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2499 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002500 }
orbitcowboy710a3322019-05-16 15:30:47 +02002501 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2502 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2503 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002504 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002505}
2506
2507
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002508void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002509{
2510 va_list va;
2511 va_start( va, format );
2512
Lee Thomason624d43f2012-10-12 10:58:48 -07002513 if ( _fp ) {
2514 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 }
2516 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002517 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 // Close out and re-start the va-args
2519 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002520 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002522 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002523 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002524 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002526 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002527}
2528
2529
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002530void XMLPrinter::Write( const char* data, size_t size )
2531{
2532 if ( _fp ) {
2533 fwrite ( data , sizeof(char), size, _fp);
2534 }
2535 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002536 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002537 memcpy( p, data, size );
2538 p[size] = 0;
2539 }
2540}
2541
2542
2543void XMLPrinter::Putc( char ch )
2544{
2545 if ( _fp ) {
2546 fputc ( ch, _fp);
2547 }
2548 else {
2549 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2550 p[0] = ch;
2551 p[1] = 0;
2552 }
2553}
2554
2555
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002556void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002559 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002561}
2562
2563
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002564void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002566 // Look for runs of bytes between entities to print.
2567 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002568
Lee Thomason624d43f2012-10-12 10:58:48 -07002569 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002570 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002572 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 // Remember, char is sometimes signed. (How many times has that bitten me?)
2574 if ( *q > 0 && *q < ENTITY_RANGE ) {
2575 // Check for entities. If one is found, flush
2576 // the stream up until the entity, write the
2577 // entity, and keep looking.
orbitcowboy710a3322019-05-16 15:30:47 +02002578 if ( flag[static_cast<unsigned char>(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002580 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002581 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002582 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002583 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002585 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002586 for( int i=0; i<NUM_ENTITIES; ++i ) {
2587 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002588 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002589 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002590 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002591 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002592 break;
2593 }
2594 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002595 if ( !entityPatternPrinted ) {
2596 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2597 TIXMLASSERT( false );
2598 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002599 ++p;
2600 }
2601 }
2602 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002603 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 }
Derek Quambe69ae62018-04-18 13:40:46 -05002605 // Flush the remaining string. This will be the entire
2606 // string if an entity wasn't found.
2607 if ( p < q ) {
2608 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002609 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Derek Quambe69ae62018-04-18 13:40:46 -05002610 Write( p, toPrint );
2611 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 }
Derek Quambe69ae62018-04-18 13:40:46 -05002613 else {
2614 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002615 }
Lee Thomason857b8682012-01-25 17:50:25 -08002616}
2617
U-Stream\Leeae25a442012-02-17 17:48:16 -08002618
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002619void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002620{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002621 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002622 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 +03002623 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002624 }
2625 if ( writeDec ) {
2626 PushDeclaration( "xml version=\"1.0\"" );
2627 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002628}
2629
2630
Uli Kusterer593a33d2014-02-01 12:48:51 +01002631void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002632{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002633 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002634 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002635
Uli Kusterer593a33d2014-02-01 12:48:51 +01002636 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002637 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002638 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002639 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002640 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002641 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002642
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002643 Write ( "<" );
2644 Write ( name );
2645
Lee Thomason624d43f2012-10-12 10:58:48 -07002646 _elementJustOpened = true;
2647 _firstElement = false;
2648 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002649}
2650
2651
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002652void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002653{
Lee Thomason624d43f2012-10-12 10:58:48 -07002654 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002655 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002656 Write( name );
2657 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002658 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002659 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002660}
2661
2662
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002663void XMLPrinter::PushAttribute( const char* name, int v )
2664{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 char buf[BUF_SIZE];
2666 XMLUtil::ToStr( v, buf, BUF_SIZE );
2667 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002668}
2669
2670
2671void XMLPrinter::PushAttribute( const char* name, unsigned v )
2672{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002673 char buf[BUF_SIZE];
2674 XMLUtil::ToStr( v, buf, BUF_SIZE );
2675 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002676}
2677
2678
Lee Thomason51c12712016-06-04 20:18:49 -07002679void XMLPrinter::PushAttribute(const char* name, int64_t v)
2680{
2681 char buf[BUF_SIZE];
2682 XMLUtil::ToStr(v, buf, BUF_SIZE);
2683 PushAttribute(name, buf);
2684}
2685
2686
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002687void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2688{
2689 char buf[BUF_SIZE];
2690 XMLUtil::ToStr(v, buf, BUF_SIZE);
2691 PushAttribute(name, buf);
2692}
2693
2694
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002695void XMLPrinter::PushAttribute( const char* name, bool v )
2696{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002697 char buf[BUF_SIZE];
2698 XMLUtil::ToStr( v, buf, BUF_SIZE );
2699 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002700}
2701
2702
2703void XMLPrinter::PushAttribute( const char* name, double v )
2704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002705 char buf[BUF_SIZE];
2706 XMLUtil::ToStr( v, buf, BUF_SIZE );
2707 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002708}
2709
2710
Uli Kustererca412e82014-02-01 13:35:05 +01002711void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002712{
Lee Thomason624d43f2012-10-12 10:58:48 -07002713 --_depth;
2714 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002715
Lee Thomason624d43f2012-10-12 10:58:48 -07002716 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002717 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002718 }
2719 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002720 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002721 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002722 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002723 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002724 Write ( "</" );
2725 Write ( name );
2726 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002727 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002728
Lee Thomason624d43f2012-10-12 10:58:48 -07002729 if ( _textDepth == _depth ) {
2730 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002731 }
Uli Kustererca412e82014-02-01 13:35:05 +01002732 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002733 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002734 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002735 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002736}
2737
2738
Dmitry-Mea092bc12014-12-23 17:57:05 +03002739void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002740{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002741 if ( !_elementJustOpened ) {
2742 return;
2743 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002744 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002745 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002746}
2747
2748
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002749void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002750{
Lee Thomason624d43f2012-10-12 10:58:48 -07002751 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002752
Dmitry-Mea092bc12014-12-23 17:57:05 +03002753 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002754 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002755 Write( "<![CDATA[" );
2756 Write( text );
2757 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002758 }
2759 else {
2760 PrintString( text, true );
2761 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002762}
2763
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002764
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002765void XMLPrinter::PushText( int64_t value )
2766{
2767 char buf[BUF_SIZE];
2768 XMLUtil::ToStr( value, buf, BUF_SIZE );
2769 PushText( buf, false );
2770}
2771
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002772
2773void XMLPrinter::PushText( uint64_t value )
2774{
2775 char buf[BUF_SIZE];
2776 XMLUtil::ToStr(value, buf, BUF_SIZE);
2777 PushText(buf, false);
2778}
2779
2780
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002781void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002782{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002783 char buf[BUF_SIZE];
2784 XMLUtil::ToStr( value, buf, BUF_SIZE );
2785 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002786}
2787
2788
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002789void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002790{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002791 char buf[BUF_SIZE];
2792 XMLUtil::ToStr( value, buf, BUF_SIZE );
2793 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002794}
2795
2796
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002797void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002798{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002799 char buf[BUF_SIZE];
2800 XMLUtil::ToStr( value, buf, BUF_SIZE );
2801 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002802}
2803
2804
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002805void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002807 char buf[BUF_SIZE];
2808 XMLUtil::ToStr( value, buf, BUF_SIZE );
2809 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002810}
2811
2812
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002813void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002814{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002815 char buf[BUF_SIZE];
2816 XMLUtil::ToStr( value, buf, BUF_SIZE );
2817 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002818}
2819
Lee Thomason5cae8972012-01-24 18:03:07 -08002820
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002821void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002822{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002823 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002824 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002825 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002826 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002827 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002828 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002829
2830 Write( "<!--" );
2831 Write( comment );
2832 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002833}
Lee Thomason751da522012-02-10 08:50:51 -08002834
2835
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002836void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002837{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002838 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002839 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002840 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002841 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002842 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002843 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002844
2845 Write( "<?" );
2846 Write( value );
2847 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002848}
2849
2850
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002851void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002852{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002853 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002854 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002855 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002856 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002857 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002858 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002859
2860 Write( "<!" );
2861 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002862 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002863}
2864
2865
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002866bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002867{
Lee Thomason624d43f2012-10-12 10:58:48 -07002868 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002869 if ( doc.HasBOM() ) {
2870 PushHeader( true, false );
2871 }
2872 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002873}
2874
2875
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002876bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002877{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002878 const XMLElement* parentElem = 0;
2879 if ( element.Parent() ) {
2880 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002881 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002882 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002883 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002884 while ( attribute ) {
2885 PushAttribute( attribute->Name(), attribute->Value() );
2886 attribute = attribute->Next();
2887 }
2888 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002889}
2890
2891
Uli Kustererca412e82014-02-01 13:35:05 +01002892bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002893{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002894 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002895 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002896}
2897
2898
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002899bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002901 PushText( text.Value(), text.CData() );
2902 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002903}
2904
2905
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002906bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002908 PushComment( comment.Value() );
2909 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002910}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002911
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002912bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002914 PushDeclaration( declaration.Value() );
2915 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002916}
2917
2918
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002919bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002920{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002921 PushUnknown( unknown.Value() );
2922 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002923}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002924
Lee Thomason685b8952012-11-12 13:00:06 -08002925} // namespace tinyxml2