blob: 9e7ff1a62ab5b8d534236f262c02625a6f34cde6 [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 }
Dan Nissenbaumd7455032019-10-24 23:57:45 -0400620 static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
621 static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
Lee Thomason7fd646a2019-08-10 17:40:19 -0700622
Dan Nissenbaumd7455032019-10-24 23:57:45 -0400623 for (int i = 0; TRUE_VALS[i]; ++i) {
624 if (StringEqual(str, TRUE_VALS[i])) {
Lee Thomason7fd646a2019-08-10 17:40:19 -0700625 *value = true;
626 return true;
627 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Dan Nissenbaumd7455032019-10-24 23:57:45 -0400629 for (int i = 0; FALSE_VALS[i]; ++i) {
630 if (StringEqual(str, FALSE_VALS[i])) {
Lee Thomason7fd646a2019-08-10 17:40:19 -0700631 *value = false;
632 return true;
633 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
635 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700636}
637
638
639bool XMLUtil::ToFloat( const char* str, float* value )
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
642 return true;
643 }
644 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700645}
646
Lee Thomason51c12712016-06-04 20:18:49 -0700647
Lee Thomason21be8822012-07-15 17:27:22 -0700648bool XMLUtil::ToDouble( const char* str, double* value )
649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
651 return true;
652 }
653 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700654}
655
656
Lee Thomason51c12712016-06-04 20:18:49 -0700657bool XMLUtil::ToInt64(const char* str, int64_t* value)
658{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700659 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
660 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
orbitcowboy710a3322019-05-16 15:30:47 +0200661 *value = static_cast<int64_t>(v);
Lee Thomason51c12712016-06-04 20:18:49 -0700662 return true;
663 }
664 return false;
665}
666
667
cugone75a5acc2019-04-11 22:03:43 -0500668bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
669 unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
670 if(TIXML_SSCANF(str, "%llu", &v) == 1) {
671 *value = (uint64_t)v;
672 return true;
673 }
674 return false;
675}
676
677
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700678char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800679{
Dmitry-Me02384662015-03-03 16:02:13 +0300680 TIXMLASSERT( node );
681 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400682 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000683 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000684 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300685 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300686 *node = 0;
687 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 return p;
689 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Dmitry-Me962083b2015-05-26 11:38:30 +0300691 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 static const char* xmlHeader = { "<?" };
693 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300695 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 static const int xmlHeaderLen = 2;
699 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300701 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
705 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400706 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += xmlHeaderLen;
711 }
712 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p += commentHeaderLen;
716 }
717 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300718 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000720 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 p += cdataHeaderLen;
722 text->SetCData( true );
723 }
724 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300725 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000726 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 p += dtdHeaderLen;
728 }
729 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300730 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000731 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 p += elementHeaderLen;
733 }
734 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300735 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000736 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000738 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740
Dmitry-Me02384662015-03-03 16:02:13 +0300741 TIXMLASSERT( returnNode );
742 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 *node = returnNode;
744 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745}
746
747
Lee Thomason751da522012-02-10 08:50:51 -0800748bool XMLDocument::Accept( XMLVisitor* visitor ) const
749{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300750 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 if ( visitor->VisitEnter( *this ) ) {
752 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
753 if ( !node->Accept( visitor ) ) {
754 break;
755 }
756 }
757 }
758 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800759}
Lee Thomason56bdd022012-02-09 18:16:58 -0800760
761
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800762// --------- XMLNode ----------- //
763
764XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 _document( doc ),
766 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200767 _value(),
kezenatorec694152016-11-26 17:21:43 +1000768 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200770 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700771 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200772 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800773{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800774}
775
776
777XMLNode::~XMLNode()
778{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( _parent ) {
781 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800783}
784
Gumichan010f1fa6d2018-02-01 14:16:24 +0100785const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200786{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300787 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530788 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530789 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200790 return _value.GetStr();
791}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800792
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793void XMLNode::SetValue( const char* str, bool staticMem )
794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 }
798 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800801}
802
Dmitry-Me3f63f212017-06-19 18:25:19 +0300803XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700804{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300805 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700806 if (!clone) return 0;
807
808 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300809 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700810 TIXMLASSERT(childClone);
811 clone->InsertEndChild(childClone);
812 }
813 return clone;
814}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800815
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800816void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800817{
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300819 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300820 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800823}
824
825
826void XMLNode::Unlink( XMLNode* child )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300830 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 if ( child == _firstChild ) {
832 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 if ( child == _lastChild ) {
835 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
Lee Thomasond923c672012-01-23 08:44:25 -0800837
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 if ( child->_prev ) {
839 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 if ( child->_next ) {
842 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
Lee Thomason8a763612017-06-16 09:30:16 -0700844 child->_next = 0;
845 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700846 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800847}
848
849
U-Stream\Leeae25a442012-02-17 17:48:16 -0800850void XMLNode::DeleteChild( XMLNode* node )
851{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300852 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100855 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700856 TIXMLASSERT(node->_prev == 0);
857 TIXMLASSERT(node->_next == 0);
858 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400859 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800860}
861
862
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800863XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
864{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300865 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300866 if ( addThis->_document != _document ) {
867 TIXMLASSERT( false );
868 return 0;
869 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800870 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( _lastChild ) {
873 TIXMLASSERT( _firstChild );
874 TIXMLASSERT( _lastChild->_next == 0 );
875 _lastChild->_next = addThis;
876 addThis->_prev = _lastChild;
877 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 TIXMLASSERT( _firstChild == 0 );
883 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800884
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 addThis->_prev = 0;
886 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800890}
891
892
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
894{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300895 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300896 if ( addThis->_document != _document ) {
897 TIXMLASSERT( false );
898 return 0;
899 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800900 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700901
Lee Thomason624d43f2012-10-12 10:58:48 -0700902 if ( _firstChild ) {
903 TIXMLASSERT( _lastChild );
904 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 _firstChild->_prev = addThis;
907 addThis->_next = _firstChild;
908 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800909
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700913 TIXMLASSERT( _lastChild == 0 );
914 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800915
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 addThis->_prev = 0;
917 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400920 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800921}
922
923
924XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
925{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300926 TIXMLASSERT( addThis );
927 if ( addThis->_document != _document ) {
928 TIXMLASSERT( false );
929 return 0;
930 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700931
Dmitry-Meabb2d042014-12-09 12:59:31 +0300932 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300935 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 return 0;
937 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300938 if ( afterThis == addThis ) {
939 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
940 // Now AddThis must disappear from it's location and then
941 // reappear between BeforeThis and OneAfterAddThis.
942 // So just leave it where it is.
943 return addThis;
944 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800945
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // The last node or the only node.
948 return InsertEndChild( addThis );
949 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800950 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 addThis->_prev = afterThis;
952 addThis->_next = afterThis->_next;
953 afterThis->_next->_prev = addThis;
954 afterThis->_next = addThis;
955 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800957}
958
959
960
961
Dmitry-Me886ad972015-07-22 11:00:51 +0300962const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800963{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300964 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300965 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 }
970 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800971}
972
973
Dmitry-Me886ad972015-07-22 11:00:51 +0300974const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800975{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300976 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300977 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300979 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 }
982 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800983}
984
985
Dmitry-Me886ad972015-07-22 11:00:51 +0300986const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300988 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300989 const XMLElement* element = node->ToElementWithName( name );
990 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400991 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
993 }
994 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995}
996
997
Dmitry-Me886ad972015-07-22 11:00:51 +0300998const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999{
Dmitry-Me2667aab2015-04-03 10:56:59 +03001000 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +03001001 const XMLElement* element = node->ToElementWithName( name );
1002 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 }
1006 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001010char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 // This is a recursive method, but thinking about it "at the current level"
1013 // it is a pretty simple flat list:
1014 // <foo/>
1015 // <!-- comment -->
1016 //
1017 // With a special case:
1018 // <foo>
1019 // </foo>
1020 // <!-- comment -->
1021 //
1022 // Where the closing element (/foo) *must* be the next thing after the opening
1023 // element, and the names must match. BUT the tricky bit is that the closing
1024 // element will be read by the child.
1025 //
1026 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1027 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001028
Lee Thomasond946dda2018-04-05 09:11:08 -07001029 XMLDocument::DepthTracker tracker(_document);
1030 if (_document->Error())
1031 return 0;
1032
1033 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001037 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001038 if ( node == 0 ) {
1039 break;
1040 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041
orbitcowboy0e7f2892019-01-15 11:28:49 +01001042 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001043
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001045 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001047 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001049 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 break;
1052 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053
orbitcowboy0e7f2892019-01-15 11:28:49 +01001054 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301055 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001056 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001057 //
1058 // Multiple declarations are allowed but all declarations
1059 // must occur before anything else.
1060 //
1061 // Optimized due to a security test case. If the first node is
1062 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001063 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001064 bool wellLocated = false;
1065
1066 if (ToDocument()) {
1067 if (FirstChild()) {
1068 wellLocated =
1069 FirstChild() &&
1070 FirstChild()->ToDeclaration() &&
1071 LastChild() &&
1072 LastChild()->ToDeclaration();
1073 }
1074 else {
1075 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301076 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001077 }
1078 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001079 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001080 DeleteNode( node );
1081 break;
1082 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301083 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301084
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001085 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001087 // We read the end tag. Return it to the parent.
1088 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001089 if ( parentEndTag ) {
1090 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001091 }
1092 node->_memPool->SetTracked(); // created and then immediately deleted.
1093 DeleteNode( node );
1094 return p;
1095 }
1096
1097 // Handle an end tag returned to this level.
1098 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001099 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001100 if ( endTag.Empty() ) {
1101 if ( ele->ClosingType() == XMLElement::OPEN ) {
1102 mismatch = true;
1103 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001105 else {
1106 if ( ele->ClosingType() != XMLElement::OPEN ) {
1107 mismatch = true;
1108 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001109 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001110 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001113 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001114 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001115 DeleteNode( node );
1116 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001117 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 }
JayXondbfdd8f2014-12-12 20:07:14 -05001119 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001122}
1123
Lee Thomason816d3fa2017-06-05 14:35:55 -07001124/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001125{
1126 if ( node == 0 ) {
1127 return;
1128 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001129 TIXMLASSERT(node->_document);
1130 if (!node->ToDocument()) {
1131 node->_document->MarkInUse(node);
1132 }
1133
Dmitry-Mee3225b12014-09-03 11:03:11 +04001134 MemPool* pool = node->_memPool;
1135 node->~XMLNode();
1136 pool->Free( node );
1137}
1138
Lee Thomason3cebdc42015-01-05 17:16:28 -08001139void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001140{
1141 TIXMLASSERT( insertThis );
1142 TIXMLASSERT( insertThis->_document == _document );
1143
Lee Thomason816d3fa2017-06-05 14:35:55 -07001144 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001145 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001146 }
1147 else {
1148 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001149 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001150 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001151}
1152
Dmitry-Meecb9b072016-10-12 16:44:59 +03001153const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1154{
1155 const XMLElement* element = this->ToElement();
1156 if ( element == 0 ) {
1157 return 0;
1158 }
1159 if ( name == 0 ) {
1160 return element;
1161 }
1162 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1163 return element;
1164 }
1165 return 0;
1166}
1167
Lee Thomason5492a1c2012-01-23 15:32:10 -08001168// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001169char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001172 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001174 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
1176 return p;
1177 }
1178 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1180 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001181 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001183
kezenator4f756162016-11-29 19:46:27 +10001184 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( p && *p ) {
1186 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001187 }
1188 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001189 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 }
1191 }
1192 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001193}
1194
1195
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001196XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 }
1201 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1202 text->SetCData( this->CData() );
1203 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001204}
1205
1206
1207bool XMLText::ShallowEqual( const XMLNode* compare ) const
1208{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001209 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001210 const XMLText* text = compare->ToText();
1211 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212}
1213
1214
Lee Thomason56bdd022012-02-09 18:16:58 -08001215bool XMLText::Accept( XMLVisitor* visitor ) const
1216{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001217 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001219}
1220
1221
Lee Thomason3f57d272012-01-11 15:30:03 -08001222// --------- XMLComment ---------- //
1223
Lee Thomasone4422302012-01-20 17:59:50 -08001224XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001225{
1226}
1227
1228
Lee Thomasonce0763e2012-01-11 15:43:54 -08001229XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001230{
Lee Thomason3f57d272012-01-11 15:30:03 -08001231}
1232
1233
kezenator4f756162016-11-29 19:46:27 +10001234char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001237 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001239 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 }
1241 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001242}
1243
1244
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 }
1250 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1251 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252}
1253
1254
1255bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001258 const XMLComment* comment = compare->ToComment();
1259 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260}
1261
1262
Lee Thomason751da522012-02-10 08:50:51 -08001263bool XMLComment::Accept( XMLVisitor* visitor ) const
1264{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001265 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001267}
Lee Thomason56bdd022012-02-09 18:16:58 -08001268
1269
Lee Thomason50f97b22012-02-11 16:33:40 -08001270// --------- XMLDeclaration ---------- //
1271
1272XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1273{
1274}
1275
1276
1277XMLDeclaration::~XMLDeclaration()
1278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001280}
1281
1282
kezenator4f756162016-11-29 19:46:27 +10001283char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001286 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001288 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 }
1290 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001291}
1292
1293
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001294XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
1299 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1300 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001301}
1302
1303
1304bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1305{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001306 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001307 const XMLDeclaration* declaration = compare->ToDeclaration();
1308 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001309}
1310
1311
1312
Lee Thomason50f97b22012-02-11 16:33:40 -08001313bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1314{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001315 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001317}
1318
1319// --------- XMLUnknown ---------- //
1320
1321XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1322{
1323}
1324
1325
1326XMLUnknown::~XMLUnknown()
1327{
1328}
1329
1330
kezenator4f756162016-11-29 19:46:27 +10001331char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001334 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001336 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 }
1338 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001339}
1340
1341
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001342XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001345 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1348 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001349}
1350
1351
1352bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1353{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001354 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001355 const XMLUnknown* unknown = compare->ToUnknown();
1356 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001357}
1358
1359
Lee Thomason50f97b22012-02-11 16:33:40 -08001360bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1361{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001362 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001364}
1365
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001366// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001367
Gumichan010f1fa6d2018-02-01 14:16:24 +01001368const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001369{
1370 return _name.GetStr();
1371}
1372
Gumichan010f1fa6d2018-02-01 14:16:24 +01001373const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001374{
1375 return _value.GetStr();
1376}
1377
kezenator4f756162016-11-29 19:46:27 +10001378char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001381 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( !p || !*p ) {
1383 return 0;
1384 }
Lee Thomason22aead12012-01-23 13:29:35 -08001385
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001387 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001388 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 return 0;
1390 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001391
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001393 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( *p != '\"' && *p != '\'' ) {
1395 return 0;
1396 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001397
orbitcowboy0e7f2892019-01-15 11:28:49 +01001398 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001400
kezenator4f756162016-11-29 19:46:27 +10001401 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001403}
1404
1405
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001406void XMLAttribute::SetName( const char* n )
1407{
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001409}
1410
1411
Lee Thomason2fa81722012-11-09 12:37:46 -08001412XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001415 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418}
1419
1420
Lee Thomason2fa81722012-11-09 12:37:46 -08001421XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001424 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
1426 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001427}
1428
1429
Lee Thomason51c12712016-06-04 20:18:49 -07001430XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1431{
1432 if (XMLUtil::ToInt64(Value(), value)) {
1433 return XML_SUCCESS;
1434 }
1435 return XML_WRONG_ATTRIBUTE_TYPE;
1436}
1437
1438
cugone75a5acc2019-04-11 22:03:43 -05001439XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1440{
1441 if(XMLUtil::ToUnsigned64(Value(), value)) {
1442 return XML_SUCCESS;
1443 }
1444 return XML_WRONG_ATTRIBUTE_TYPE;
1445}
1446
1447
Lee Thomason2fa81722012-11-09 12:37:46 -08001448XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001451 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001454}
1455
1456
Lee Thomason2fa81722012-11-09 12:37:46 -08001457XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001460 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001463}
1464
1465
Lee Thomason2fa81722012-11-09 12:37:46 -08001466XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001469 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
1471 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001472}
1473
1474
1475void XMLAttribute::SetAttribute( const char* v )
1476{
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001478}
1479
1480
Lee Thomason1ff38e02012-02-14 18:18:16 -08001481void XMLAttribute::SetAttribute( int v )
1482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 char buf[BUF_SIZE];
1484 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001486}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487
1488
1489void XMLAttribute::SetAttribute( unsigned v )
1490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 char buf[BUF_SIZE];
1492 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
1496
Lee Thomason51c12712016-06-04 20:18:49 -07001497void XMLAttribute::SetAttribute(int64_t v)
1498{
1499 char buf[BUF_SIZE];
1500 XMLUtil::ToStr(v, buf, BUF_SIZE);
1501 _value.SetStr(buf);
1502}
1503
Lee Thomasoneffdf952019-08-10 17:49:42 -07001504void XMLAttribute::SetAttribute(uint64_t v)
1505{
1506 char buf[BUF_SIZE];
1507 XMLUtil::ToStr(v, buf, BUF_SIZE);
1508 _value.SetStr(buf);
1509}
Lee Thomason51c12712016-06-04 20:18:49 -07001510
1511
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001512void XMLAttribute::SetAttribute( bool v )
1513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 char buf[BUF_SIZE];
1515 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001517}
1518
1519void XMLAttribute::SetAttribute( double v )
1520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 char buf[BUF_SIZE];
1522 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001524}
1525
1526void XMLAttribute::SetAttribute( float v )
1527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 char buf[BUF_SIZE];
1529 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001531}
1532
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001533
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001534// --------- XMLElement ---------- //
1535XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001536 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001538{
1539}
1540
1541
1542XMLElement::~XMLElement()
1543{
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 while( _rootAttribute ) {
1545 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001546 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001549}
1550
1551
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001552const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1553{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001554 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1556 return a;
1557 }
1558 }
1559 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001560}
1561
1562
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001563const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 const XMLAttribute* a = FindAttribute( name );
1566 if ( !a ) {
1567 return 0;
1568 }
1569 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1570 return a->Value();
1571 }
1572 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001573}
1574
Gumichan010f1fa6d2018-02-01 14:16:24 +01001575int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001576{
1577 int i = defaultValue;
1578 QueryIntAttribute(name, &i);
1579 return i;
1580}
1581
Gumichan010f1fa6d2018-02-01 14:16:24 +01001582unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001583{
1584 unsigned i = defaultValue;
1585 QueryUnsignedAttribute(name, &i);
1586 return i;
1587}
1588
Gumichan010f1fa6d2018-02-01 14:16:24 +01001589int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001590{
1591 int64_t i = defaultValue;
1592 QueryInt64Attribute(name, &i);
1593 return i;
1594}
1595
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01001596uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1597{
1598 uint64_t i = defaultValue;
1599 QueryUnsigned64Attribute(name, &i);
1600 return i;
1601}
1602
Gumichan010f1fa6d2018-02-01 14:16:24 +01001603bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001604{
1605 bool b = defaultValue;
1606 QueryBoolAttribute(name, &b);
1607 return b;
1608}
1609
Gumichan010f1fa6d2018-02-01 14:16:24 +01001610double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001611{
1612 double d = defaultValue;
1613 QueryDoubleAttribute(name, &d);
1614 return d;
1615}
1616
Gumichan010f1fa6d2018-02-01 14:16:24 +01001617float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001618{
1619 float f = defaultValue;
1620 QueryFloatAttribute(name, &f);
1621 return f;
1622}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001623
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001624const char* XMLElement::GetText() const
1625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001627 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 }
1629 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001630}
1631
1632
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001633void XMLElement::SetText( const char* inText )
1634{
Uli Kusterer869bb592014-01-21 01:36:16 +01001635 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001636 FirstChild()->SetValue( inText );
1637 else {
1638 XMLText* theText = GetDocument()->NewText( inText );
1639 InsertFirstChild( theText );
1640 }
1641}
1642
Lee Thomason5bb2d802014-01-24 10:42:57 -08001643
Gumichan010f1fa6d2018-02-01 14:16:24 +01001644void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001645{
1646 char buf[BUF_SIZE];
1647 XMLUtil::ToStr( v, buf, BUF_SIZE );
1648 SetText( buf );
1649}
1650
1651
Gumichan010f1fa6d2018-02-01 14:16:24 +01001652void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001653{
1654 char buf[BUF_SIZE];
1655 XMLUtil::ToStr( v, buf, BUF_SIZE );
1656 SetText( buf );
1657}
1658
1659
Lee Thomason51c12712016-06-04 20:18:49 -07001660void XMLElement::SetText(int64_t v)
1661{
1662 char buf[BUF_SIZE];
1663 XMLUtil::ToStr(v, buf, BUF_SIZE);
1664 SetText(buf);
1665}
1666
cugone47e229e2019-04-12 17:27:28 -05001667void XMLElement::SetText(uint64_t v) {
1668 char buf[BUF_SIZE];
1669 XMLUtil::ToStr(v, buf, BUF_SIZE);
1670 SetText(buf);
1671}
1672
Lee Thomason51c12712016-06-04 20:18:49 -07001673
1674void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001675{
1676 char buf[BUF_SIZE];
1677 XMLUtil::ToStr( v, buf, BUF_SIZE );
1678 SetText( buf );
1679}
1680
1681
Gumichan010f1fa6d2018-02-01 14:16:24 +01001682void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001683{
1684 char buf[BUF_SIZE];
1685 XMLUtil::ToStr( v, buf, BUF_SIZE );
1686 SetText( buf );
1687}
1688
1689
Gumichan010f1fa6d2018-02-01 14:16:24 +01001690void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001691{
1692 char buf[BUF_SIZE];
1693 XMLUtil::ToStr( v, buf, BUF_SIZE );
1694 SetText( buf );
1695}
1696
1697
MortenMacFly4ee49f12013-01-14 20:03:14 +01001698XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001699{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001701 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001702 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 return XML_SUCCESS;
1704 }
1705 return XML_CAN_NOT_CONVERT_TEXT;
1706 }
1707 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001708}
1709
1710
MortenMacFly4ee49f12013-01-14 20:03:14 +01001711XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001714 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001715 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 return XML_SUCCESS;
1717 }
1718 return XML_CAN_NOT_CONVERT_TEXT;
1719 }
1720 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001721}
1722
1723
Lee Thomason51c12712016-06-04 20:18:49 -07001724XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1725{
1726 if (FirstChild() && FirstChild()->ToText()) {
1727 const char* t = FirstChild()->Value();
1728 if (XMLUtil::ToInt64(t, ival)) {
1729 return XML_SUCCESS;
1730 }
1731 return XML_CAN_NOT_CONVERT_TEXT;
1732 }
1733 return XML_NO_TEXT_NODE;
1734}
1735
1736
cugone1dbfe312019-04-12 17:33:49 -05001737XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const
1738{
cugone47e229e2019-04-12 17:27:28 -05001739 if(FirstChild() && FirstChild()->ToText()) {
1740 const char* t = FirstChild()->Value();
1741 if(XMLUtil::ToUnsigned64(t, ival)) {
1742 return XML_SUCCESS;
1743 }
1744 return XML_CAN_NOT_CONVERT_TEXT;
1745 }
1746 return XML_NO_TEXT_NODE;
1747}
1748
1749
MortenMacFly4ee49f12013-01-14 20:03:14 +01001750XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001753 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001754 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 return XML_SUCCESS;
1756 }
1757 return XML_CAN_NOT_CONVERT_TEXT;
1758 }
1759 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001760}
1761
1762
MortenMacFly4ee49f12013-01-14 20:03:14 +01001763XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001764{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001766 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001767 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 return XML_SUCCESS;
1769 }
1770 return XML_CAN_NOT_CONVERT_TEXT;
1771 }
1772 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001773}
1774
1775
MortenMacFly4ee49f12013-01-14 20:03:14 +01001776XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001777{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001779 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001780 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 return XML_SUCCESS;
1782 }
1783 return XML_CAN_NOT_CONVERT_TEXT;
1784 }
1785 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001786}
1787
Josh Wittnercf3dd092016-10-11 18:57:17 -07001788int XMLElement::IntText(int defaultValue) const
1789{
1790 int i = defaultValue;
1791 QueryIntText(&i);
1792 return i;
1793}
1794
1795unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1796{
1797 unsigned i = defaultValue;
1798 QueryUnsignedText(&i);
1799 return i;
1800}
1801
1802int64_t XMLElement::Int64Text(int64_t defaultValue) const
1803{
1804 int64_t i = defaultValue;
1805 QueryInt64Text(&i);
1806 return i;
1807}
1808
cugone1dbfe312019-04-12 17:33:49 -05001809uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1810{
1811 uint64_t i = defaultValue;
1812 QueryUnsigned64Text(&i);
1813 return i;
1814}
1815
Josh Wittnercf3dd092016-10-11 18:57:17 -07001816bool XMLElement::BoolText(bool defaultValue) const
1817{
1818 bool b = defaultValue;
1819 QueryBoolText(&b);
1820 return b;
1821}
1822
1823double XMLElement::DoubleText(double defaultValue) const
1824{
1825 double d = defaultValue;
1826 QueryDoubleText(&d);
1827 return d;
1828}
1829
1830float XMLElement::FloatText(float defaultValue) const
1831{
1832 float f = defaultValue;
1833 QueryFloatText(&f);
1834 return f;
1835}
Lee Thomason21be8822012-07-15 17:27:22 -07001836
1837
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001838XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1839{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 XMLAttribute* last = 0;
1841 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1846 break;
1847 }
1848 }
1849 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001850 attrib = CreateAttribute();
1851 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001853 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 }
1856 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001857 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
1860 attrib->SetName( name );
1861 }
1862 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001863}
1864
1865
U-Stream\Leeae25a442012-02-17 17:48:16 -08001866void XMLElement::DeleteAttribute( const char* name )
1867{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1871 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
1874 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001877 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 break;
1879 }
1880 prev = a;
1881 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001882}
1883
1884
kezenator4f756162016-11-29 19:46:27 +10001885char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001886{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001888
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 // Read the attributes.
1890 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001892 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001893 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 return 0;
1895 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001896
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001898 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001899 XMLAttribute* attrib = CreateAttribute();
1900 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001901 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001902
orbitcowboy0e7f2892019-01-15 11:28:49 +01001903 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001904
kezenator4f756162016-11-29 19:46:27 +10001905 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001907 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001908 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return 0;
1910 }
1911 // There is a minor bug here: if the attribute in the source xml
1912 // document is duplicated, it will not be detected and the
1913 // attribute will be doubly added. However, tracking the 'prevAttribute'
1914 // avoids re-scanning the attribute list. Preferring performance for
1915 // now, may reconsider in the future.
1916 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001917 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
1920 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001921 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 prevAttribute = attrib;
1925 }
1926 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 else if ( *p == '>' ) {
1928 ++p;
1929 break;
1930 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001931 // end of the tag
1932 else if ( *p == '/' && *(p+1) == '>' ) {
1933 _closingType = CLOSED;
1934 return p+2; // done; sealed element.
1935 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001937 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 return 0;
1939 }
1940 }
1941 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001942}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001943
Dmitry-Mee3225b12014-09-03 11:03:11 +04001944void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1945{
1946 if ( attribute == 0 ) {
1947 return;
1948 }
1949 MemPool* pool = attribute->_memPool;
1950 attribute->~XMLAttribute();
1951 pool->Free( attribute );
1952}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001953
Dmitry-Mea60caa22016-11-22 18:28:08 +03001954XMLAttribute* XMLElement::CreateAttribute()
1955{
1956 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1957 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001958 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001959 attrib->_memPool = &_document->_attributePool;
1960 attrib->_memPool->SetTracked();
1961 return attrib;
1962}
1963
ngc92e6202452019-12-03 16:25:53 +01001964
Lee Thomasone4442682020-03-01 17:10:38 -08001965XMLElement* XMLElement::InsertNewChildElement(const char* name)
ngc92e6202452019-12-03 16:25:53 +01001966{
Lee Thomasone4442682020-03-01 17:10:38 -08001967 XMLElement* node = _document->NewElement(name);
1968 return InsertEndChild(node) ? node : 0;
ngc92e6202452019-12-03 16:25:53 +01001969}
1970
Lee Thomasone4442682020-03-01 17:10:38 -08001971XMLComment* XMLElement::InsertNewComment(const char* comment)
ngc92e6202452019-12-03 16:25:53 +01001972{
Lee Thomasone4442682020-03-01 17:10:38 -08001973 XMLComment* node = _document->NewComment(comment);
1974 return InsertEndChild(node) ? node : 0;
ngc92e6202452019-12-03 16:25:53 +01001975}
1976
Lee Thomasone4442682020-03-01 17:10:38 -08001977XMLText* XMLElement::InsertNewText(const char* text)
ngc92e6202452019-12-03 16:25:53 +01001978{
Lee Thomasone4442682020-03-01 17:10:38 -08001979 XMLText* node = _document->NewText(text);
1980 return InsertEndChild(node) ? node : 0;
ngc92e6202452019-12-03 16:25:53 +01001981}
1982
Lee Thomasone4442682020-03-01 17:10:38 -08001983XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
ngc92e6202452019-12-03 16:25:53 +01001984{
Lee Thomasone4442682020-03-01 17:10:38 -08001985 XMLDeclaration* node = _document->NewDeclaration(text);
1986 return InsertEndChild(node) ? node : 0;
ngc92e6202452019-12-03 16:25:53 +01001987}
1988
Lee Thomasone4442682020-03-01 17:10:38 -08001989XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
ngc92e6202452019-12-03 16:25:53 +01001990{
Lee Thomasone4442682020-03-01 17:10:38 -08001991 XMLUnknown* node = _document->NewUnknown(text);
1992 return InsertEndChild(node) ? node : 0;
ngc92e6202452019-12-03 16:25:53 +01001993}
1994
1995
1996
Lee Thomason67d61312012-01-24 16:01:51 -08001997//
1998// <ele></ele>
1999// <ele>foo<b>bar</b></ele>
2000//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002001char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08002002{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10002004 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08002005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 // The closing element is the </element> form. It is
2007 // parsed just like a regular element then deleted from
2008 // the DOM.
2009 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 ++p;
2012 }
Lee Thomason67d61312012-01-24 16:01:51 -08002013
Lee Thomason624d43f2012-10-12 10:58:48 -07002014 p = _value.ParseName( p );
2015 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 return 0;
2017 }
Lee Thomason67d61312012-01-24 16:01:51 -08002018
kezenator4f756162016-11-29 19:46:27 +10002019 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03002020 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 return p;
2022 }
Lee Thomason67d61312012-01-24 16:01:51 -08002023
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03002024 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08002026}
2027
2028
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002029
2030XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 }
2035 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
2036 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2037 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
2038 }
2039 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002040}
2041
2042
2043bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2044{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002045 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03002047 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002048
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 const XMLAttribute* a=FirstAttribute();
2050 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002051
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 while ( a && b ) {
2053 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2054 return false;
2055 }
2056 a = a->Next();
2057 b = b->Next();
2058 }
2059 if ( a || b ) {
2060 // different count
2061 return false;
2062 }
2063 return true;
2064 }
2065 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002066}
2067
2068
Lee Thomason751da522012-02-10 08:50:51 -08002069bool XMLElement::Accept( XMLVisitor* visitor ) const
2070{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002071 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2074 if ( !node->Accept( visitor ) ) {
2075 break;
2076 }
2077 }
2078 }
2079 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08002080}
Lee Thomason56bdd022012-02-09 18:16:58 -08002081
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002082
Lee Thomason3f57d272012-01-11 15:30:03 -08002083// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07002084
2085// Warning: List must match 'enum XMLError'
2086const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2087 "XML_SUCCESS",
2088 "XML_NO_ATTRIBUTE",
2089 "XML_WRONG_ATTRIBUTE_TYPE",
2090 "XML_ERROR_FILE_NOT_FOUND",
2091 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2092 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07002093 "XML_ERROR_PARSING_ELEMENT",
2094 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07002095 "XML_ERROR_PARSING_TEXT",
2096 "XML_ERROR_PARSING_CDATA",
2097 "XML_ERROR_PARSING_COMMENT",
2098 "XML_ERROR_PARSING_DECLARATION",
2099 "XML_ERROR_PARSING_UNKNOWN",
2100 "XML_ERROR_EMPTY_DOCUMENT",
2101 "XML_ERROR_MISMATCHED_ELEMENT",
2102 "XML_ERROR_PARSING",
2103 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002104 "XML_NO_TEXT_NODE",
2105 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002106};
2107
2108
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002109XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002111 _writeBOM( false ),
2112 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002113 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002114 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002115 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002116 _errorLineNum( 0 ),
2117 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002118 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002119 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002120 _unlinked(),
2121 _elementPool(),
2122 _attributePool(),
2123 _textPool(),
2124 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002125{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002126 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2127 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002128}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002129
2130
Lee Thomason3f57d272012-01-11 15:30:03 -08002131XMLDocument::~XMLDocument()
2132{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002133 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002134}
2135
2136
orbitcowboy73f54092019-08-14 09:30:30 +02002137void XMLDocument::MarkInUse(const XMLNode* const node)
Lee Thomason816d3fa2017-06-05 14:35:55 -07002138{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002139 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002140 TIXMLASSERT(node->_parent == 0);
2141
2142 for (int i = 0; i < _unlinked.Size(); ++i) {
2143 if (node == _unlinked[i]) {
2144 _unlinked.SwapRemove(i);
2145 break;
2146 }
2147 }
2148}
2149
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002150void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002151{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002152 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002153 while( _unlinked.Size()) {
2154 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2155 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002156
Peter Matula50689912018-01-09 12:52:26 +01002157#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002158 const bool hadError = Error();
2159#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002160 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002161
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 delete [] _charBuffer;
2163 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002164 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002165
2166#if 0
2167 _textPool.Trace( "text" );
2168 _elementPool.Trace( "element" );
2169 _commentPool.Trace( "comment" );
2170 _attributePool.Trace( "attribute" );
2171#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002172
Peter Matula50689912018-01-09 12:52:26 +01002173#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002174 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002175 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2176 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2177 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2178 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2179 }
2180#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002181}
2182
Lee Thomason3f57d272012-01-11 15:30:03 -08002183
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002184void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002185{
2186 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002187 if (target == this) {
2188 return; // technically success - a no-op.
2189 }
Lee Thomason7085f002017-06-01 18:09:43 -07002190
2191 target->Clear();
2192 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2193 target->InsertEndChild(node->DeepClone(target));
2194 }
2195}
2196
Lee Thomason2c85a712012-01-31 08:24:24 -08002197XMLElement* XMLDocument::NewElement( const char* name )
2198{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002199 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 ele->SetName( name );
2201 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002202}
2203
2204
Lee Thomason1ff38e02012-02-14 18:18:16 -08002205XMLComment* XMLDocument::NewComment( const char* str )
2206{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002207 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 comment->SetValue( str );
2209 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002210}
2211
2212
2213XMLText* XMLDocument::NewText( const char* str )
2214{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002215 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 text->SetValue( str );
2217 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002218}
2219
2220
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002221XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2222{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002223 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2225 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002226}
2227
2228
2229XMLUnknown* XMLDocument::NewUnknown( const char* str )
2230{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002231 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 unk->SetValue( str );
2233 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002234}
2235
Dmitry-Me01578db2014-08-19 10:18:48 +04002236static FILE* callfopen( const char* filepath, const char* mode )
2237{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002238 TIXMLASSERT( filepath );
2239 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002240#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2241 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002242 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002243 if ( err ) {
2244 return 0;
2245 }
2246#else
2247 FILE* fp = fopen( filepath, mode );
2248#endif
2249 return fp;
2250}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002251
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002252void XMLDocument::DeleteNode( XMLNode* node ) {
2253 TIXMLASSERT( node );
2254 TIXMLASSERT(node->_document == this );
2255 if (node->_parent) {
2256 node->_parent->DeleteChild( node );
2257 }
2258 else {
2259 // Isn't in the tree.
2260 // Use the parent delete.
2261 // Also, we need to mark it tracked: we 'know'
2262 // it was never used.
2263 node->_memPool->SetTracked();
2264 // Call the static XMLNode version:
2265 XMLNode::DeleteNode(node);
2266 }
2267}
2268
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002269
Lee Thomason2fa81722012-11-09 12:37:46 -08002270XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002271{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002272 if ( !filename ) {
2273 TIXMLASSERT( false );
2274 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2275 return _errorID;
2276 }
2277
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002278 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002279 FILE* fp = callfopen( filename, "rb" );
2280 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002281 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002282 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 }
2284 LoadFile( fp );
2285 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002287}
2288
Dmitry-Me901fed52015-09-25 10:29:51 +03002289// This is likely overengineered template art to have a check that unsigned long value incremented
2290// by one still fits into size_t. If size_t type is larger than unsigned long type
2291// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2292// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2293// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2294// types sizes relate to each other.
2295template
2296<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2297struct LongFitsIntoSizeTMinusOne {
2298 static bool Fits( unsigned long value )
2299 {
orbitcowboy710a3322019-05-16 15:30:47 +02002300 return value < static_cast<size_t>(-1);
Dmitry-Me901fed52015-09-25 10:29:51 +03002301 }
2302};
2303
2304template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002305struct LongFitsIntoSizeTMinusOne<false> {
2306 static bool Fits( unsigned long )
2307 {
2308 return true;
2309 }
2310};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002311
Lee Thomason2fa81722012-11-09 12:37:46 -08002312XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002313{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002314 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002315
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002316 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002317 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002318 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002319 return _errorID;
2320 }
2321
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002323 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002325 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002326 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002327 return _errorID;
2328 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002329 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002330
Dmitry-Me901fed52015-09-25 10:29:51 +03002331 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002332 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002333 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002334 return _errorID;
2335 }
2336
Dmitry-Me72801b82015-05-07 09:41:39 +03002337 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002338 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002339 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002341
Dmitry-Me72801b82015-05-07 09:41:39 +03002342 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002343 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002344 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002345 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002346 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002347 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002348 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002350
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002352
Dmitry-Me97476b72015-01-01 16:15:57 +03002353 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002355}
2356
2357
Lee Thomason2fa81722012-11-09 12:37:46 -08002358XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002359{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002360 if ( !filename ) {
2361 TIXMLASSERT( false );
2362 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2363 return _errorID;
2364 }
2365
Dmitry-Me01578db2014-08-19 10:18:48 +04002366 FILE* fp = callfopen( filename, "w" );
2367 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002368 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 }
2371 SaveFile(fp, compact);
2372 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002374}
2375
2376
Lee Thomason2fa81722012-11-09 12:37:46 -08002377XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002378{
Ant Mitchell189198f2015-03-24 16:20:36 +00002379 // Clear any error from the last save, otherwise it will get reported
2380 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002381 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 XMLPrinter stream( fp, compact );
2383 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002385}
2386
Lee Thomason1ff38e02012-02-14 18:18:16 -08002387
Lee Thomason2fa81722012-11-09 12:37:46 -08002388XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002389{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002390 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002391
Lee Thomason82d32002014-02-21 22:47:18 -08002392 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002393 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002394 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 }
orbitcowboy710a3322019-05-16 15:30:47 +02002396 if ( len == static_cast<size_t>(-1) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 len = strlen( p );
2398 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002399 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002400 _charBuffer = new char[ len+1 ];
2401 memcpy( _charBuffer, p, len );
2402 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002403
Dmitry-Me97476b72015-01-01 16:15:57 +03002404 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002405 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002406 // clean up now essentially dangling memory.
2407 // and the parse fail can put objects in the
2408 // pools that are dead and inaccessible.
2409 DeleteChildren();
2410 _elementPool.Clear();
2411 _attributePool.Clear();
2412 _textPool.Clear();
2413 _commentPool.Clear();
2414 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002415 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002416}
2417
2418
PKEuS1c5f99e2013-07-06 11:28:39 +02002419void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002420{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002421 if ( streamer ) {
2422 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002424 else {
2425 XMLPrinter stdoutStreamer( stdout );
2426 Accept( &stdoutStreamer );
2427 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002428}
2429
2430
Lee Thomasonaa188392017-09-19 17:54:31 -07002431void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002432{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002433 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002434 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002435 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002436 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002437
orbitcowboy0e7f2892019-01-15 11:28:49 +01002438 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002439 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002440
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002441 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002442 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 -07002443
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002444 if (format) {
2445 size_t len = strlen(buffer);
2446 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2447 len = strlen(buffer);
2448
2449 va_list va;
2450 va_start(va, format);
2451 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2452 va_end(va);
2453 }
2454 _errorStr.SetStr(buffer);
2455 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002456}
2457
Lee Thomasonaa188392017-09-19 17:54:31 -07002458
Lee Thomasone90e9012016-12-24 07:34:39 -08002459/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002460{
kezenator5a700712016-11-26 13:54:42 +10002461 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2462 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002463 TIXMLASSERT( errorName && errorName[0] );
2464 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002465}
Lee Thomason5cae8972012-01-24 18:03:07 -08002466
Gumichan010f1fa6d2018-02-01 14:16:24 +01002467const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002468{
Lee Thomasonaa188392017-09-19 17:54:31 -07002469 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002470}
2471
Lee Thomasonf49b9652017-10-11 10:57:49 -07002472
2473void XMLDocument::PrintError() const
2474{
2475 printf("%s\n", ErrorStr());
2476}
2477
kezenator5a700712016-11-26 13:54:42 +10002478const char* XMLDocument::ErrorName() const
2479{
Lee Thomasone90e9012016-12-24 07:34:39 -08002480 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002481}
2482
Dmitry-Me97476b72015-01-01 16:15:57 +03002483void XMLDocument::Parse()
2484{
2485 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2486 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002487 _parseCurLineNum = 1;
2488 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002489 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002490 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002491 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002492 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002493 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002494 return;
2495 }
kezenator4f756162016-11-29 19:46:27 +10002496 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002497}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002498
Lee Thomasonf928c352018-04-05 09:24:20 -07002499void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002500{
2501 _parsingDepth++;
2502 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002503 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002504 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002505}
2506
Lee Thomasonf928c352018-04-05 09:24:20 -07002507void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002508{
2509 TIXMLASSERT(_parsingDepth > 0);
2510 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002511}
2512
PKEuS1bfb9542013-08-04 13:51:17 +02002513XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002515 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002516 _firstElement( true ),
2517 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002518 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002519 _textDepth( -1 ),
2520 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002521 _compactMode( compact ),
2522 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002525 _entityFlag[i] = false;
2526 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 }
2528 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002529 const char entityValue = entities[i].value;
orbitcowboy710a3322019-05-16 15:30:47 +02002530 const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
Dmitry-Mea28eb072017-08-25 18:34:18 +03002531 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2532 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 }
orbitcowboy710a3322019-05-16 15:30:47 +02002534 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2535 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2536 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002537 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002538}
2539
2540
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002541void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002542{
2543 va_list va;
2544 va_start( va, format );
2545
Lee Thomason624d43f2012-10-12 10:58:48 -07002546 if ( _fp ) {
2547 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 }
2549 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002550 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 // Close out and re-start the va-args
2552 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002553 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002554 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002555 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002556 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002557 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002559 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002560}
2561
2562
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002563void XMLPrinter::Write( const char* data, size_t size )
2564{
2565 if ( _fp ) {
2566 fwrite ( data , sizeof(char), size, _fp);
2567 }
2568 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002569 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002570 memcpy( p, data, size );
2571 p[size] = 0;
2572 }
2573}
2574
2575
2576void XMLPrinter::Putc( char ch )
2577{
2578 if ( _fp ) {
2579 fputc ( ch, _fp);
2580 }
2581 else {
2582 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2583 p[0] = ch;
2584 p[1] = 0;
2585 }
2586}
2587
2588
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002589void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002591 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002592 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002594}
2595
2596
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002597void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002599 // Look for runs of bytes between entities to print.
2600 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002601
Lee Thomason624d43f2012-10-12 10:58:48 -07002602 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002603 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002605 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002606 // Remember, char is sometimes signed. (How many times has that bitten me?)
2607 if ( *q > 0 && *q < ENTITY_RANGE ) {
2608 // Check for entities. If one is found, flush
2609 // the stream up until the entity, write the
2610 // entity, and keep looking.
orbitcowboy710a3322019-05-16 15:30:47 +02002611 if ( flag[static_cast<unsigned char>(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002613 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002614 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002615 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002616 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002618 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 for( int i=0; i<NUM_ENTITIES; ++i ) {
2620 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002621 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002622 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002623 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002624 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002625 break;
2626 }
2627 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002628 if ( !entityPatternPrinted ) {
2629 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2630 TIXMLASSERT( false );
2631 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 ++p;
2633 }
2634 }
2635 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002636 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002637 }
Derek Quambe69ae62018-04-18 13:40:46 -05002638 // Flush the remaining string. This will be the entire
2639 // string if an entity wasn't found.
2640 if ( p < q ) {
2641 const size_t delta = q - p;
orbitcowboy710a3322019-05-16 15:30:47 +02002642 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
Derek Quambe69ae62018-04-18 13:40:46 -05002643 Write( p, toPrint );
2644 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002645 }
Derek Quambe69ae62018-04-18 13:40:46 -05002646 else {
2647 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002648 }
Lee Thomason857b8682012-01-25 17:50:25 -08002649}
2650
U-Stream\Leeae25a442012-02-17 17:48:16 -08002651
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002652void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002654 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002655 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 +03002656 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002657 }
2658 if ( writeDec ) {
2659 PushDeclaration( "xml version=\"1.0\"" );
2660 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002661}
2662
2663
Uli Kusterer593a33d2014-02-01 12:48:51 +01002664void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002665{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002666 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002667 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002668
Uli Kusterer593a33d2014-02-01 12:48:51 +01002669 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002670 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002671 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002673
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002674 Write ( "<" );
2675 Write ( name );
2676
Lee Thomason624d43f2012-10-12 10:58:48 -07002677 _elementJustOpened = true;
2678 _firstElement = false;
2679 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002680}
2681
2682
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002683void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002684{
Lee Thomason624d43f2012-10-12 10:58:48 -07002685 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002686 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002687 Write( name );
2688 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002690 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002691}
2692
2693
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002694void XMLPrinter::PushAttribute( const char* name, int v )
2695{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 char buf[BUF_SIZE];
2697 XMLUtil::ToStr( v, buf, BUF_SIZE );
2698 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002699}
2700
2701
2702void XMLPrinter::PushAttribute( const char* name, unsigned v )
2703{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002704 char buf[BUF_SIZE];
2705 XMLUtil::ToStr( v, buf, BUF_SIZE );
2706 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002707}
2708
2709
Lee Thomason51c12712016-06-04 20:18:49 -07002710void XMLPrinter::PushAttribute(const char* name, int64_t v)
2711{
2712 char buf[BUF_SIZE];
2713 XMLUtil::ToStr(v, buf, BUF_SIZE);
2714 PushAttribute(name, buf);
2715}
2716
2717
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002718void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2719{
2720 char buf[BUF_SIZE];
2721 XMLUtil::ToStr(v, buf, BUF_SIZE);
2722 PushAttribute(name, buf);
2723}
2724
2725
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002726void XMLPrinter::PushAttribute( const char* name, bool v )
2727{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002728 char buf[BUF_SIZE];
2729 XMLUtil::ToStr( v, buf, BUF_SIZE );
2730 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002731}
2732
2733
2734void XMLPrinter::PushAttribute( const char* name, double v )
2735{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002736 char buf[BUF_SIZE];
2737 XMLUtil::ToStr( v, buf, BUF_SIZE );
2738 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002739}
2740
2741
Uli Kustererca412e82014-02-01 13:35:05 +01002742void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002743{
Lee Thomason624d43f2012-10-12 10:58:48 -07002744 --_depth;
2745 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002746
Lee Thomason624d43f2012-10-12 10:58:48 -07002747 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002748 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002749 }
2750 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002751 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002752 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002753 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002754 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002755 Write ( "</" );
2756 Write ( name );
2757 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002758 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002759
Lee Thomason624d43f2012-10-12 10:58:48 -07002760 if ( _textDepth == _depth ) {
2761 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002762 }
Uli Kustererca412e82014-02-01 13:35:05 +01002763 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002764 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002765 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002766 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002767}
2768
2769
Dmitry-Mea092bc12014-12-23 17:57:05 +03002770void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002771{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002772 if ( !_elementJustOpened ) {
2773 return;
2774 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002775 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002776 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002777}
2778
2779
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002780void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002781{
Lee Thomason624d43f2012-10-12 10:58:48 -07002782 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002783
Dmitry-Mea092bc12014-12-23 17:57:05 +03002784 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002785 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002786 Write( "<![CDATA[" );
2787 Write( text );
2788 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002789 }
2790 else {
2791 PrintString( text, true );
2792 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002793}
2794
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002795
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002796void XMLPrinter::PushText( int64_t value )
2797{
2798 char buf[BUF_SIZE];
2799 XMLUtil::ToStr( value, buf, BUF_SIZE );
2800 PushText( buf, false );
2801}
2802
aaronkirkham07@gmail.comc341cea2019-05-22 00:05:27 +01002803
2804void XMLPrinter::PushText( uint64_t value )
2805{
2806 char buf[BUF_SIZE];
2807 XMLUtil::ToStr(value, buf, BUF_SIZE);
2808 PushText(buf, false);
2809}
2810
2811
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002812void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002813{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002814 char buf[BUF_SIZE];
2815 XMLUtil::ToStr( value, buf, BUF_SIZE );
2816 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002817}
2818
2819
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002820void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002821{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002822 char buf[BUF_SIZE];
2823 XMLUtil::ToStr( value, buf, BUF_SIZE );
2824 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002825}
2826
2827
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002828void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002830 char buf[BUF_SIZE];
2831 XMLUtil::ToStr( value, buf, BUF_SIZE );
2832 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002833}
2834
2835
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002836void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002837{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002838 char buf[BUF_SIZE];
2839 XMLUtil::ToStr( value, buf, BUF_SIZE );
2840 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002841}
2842
2843
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002844void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002845{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002846 char buf[BUF_SIZE];
2847 XMLUtil::ToStr( value, buf, BUF_SIZE );
2848 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002849}
2850
Lee Thomason5cae8972012-01-24 18:03:07 -08002851
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002852void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002853{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002854 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002855 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002856 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002857 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002858 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002859 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002860
2861 Write( "<!--" );
2862 Write( comment );
2863 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002864}
Lee Thomason751da522012-02-10 08:50:51 -08002865
2866
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002867void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002868{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002869 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002870 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002871 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002872 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002873 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002874 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002875
2876 Write( "<?" );
2877 Write( value );
2878 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002879}
2880
2881
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002882void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002883{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002884 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002885 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002886 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002887 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002888 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002889 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002890
2891 Write( "<!" );
2892 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002893 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002894}
2895
2896
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002897bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002898{
Lee Thomason624d43f2012-10-12 10:58:48 -07002899 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002900 if ( doc.HasBOM() ) {
2901 PushHeader( true, false );
2902 }
2903 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002904}
2905
2906
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002907bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002908{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002909 const XMLElement* parentElem = 0;
2910 if ( element.Parent() ) {
2911 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002912 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002913 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002914 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002915 while ( attribute ) {
2916 PushAttribute( attribute->Name(), attribute->Value() );
2917 attribute = attribute->Next();
2918 }
2919 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002920}
2921
2922
Uli Kustererca412e82014-02-01 13:35:05 +01002923bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002924{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002925 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002926 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002927}
2928
2929
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002930bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002931{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002932 PushText( text.Value(), text.CData() );
2933 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002934}
2935
2936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002937bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002939 PushComment( comment.Value() );
2940 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002941}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002942
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002943bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002944{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002945 PushDeclaration( declaration.Value() );
2946 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002947}
2948
2949
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002950bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002952 PushUnknown( unknown.Value() );
2953 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002954}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002955
Lee Thomason685b8952012-11-12 13:00:06 -08002956} // namespace tinyxml2