blob: 74265fe828dd5608fa59e0eb1dd92ab1e0b4153d [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 );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 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 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 char endChar = *endTag;
201 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;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300313 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
448 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
Lee Thomason51c12712016-06-04 20:18:49 -0700585void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
591
Lee Thomason21be8822012-07-15 17:27:22 -0700592bool XMLUtil::ToInt( const char* str, int* value )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608bool XMLUtil::ToBool( const char* str, bool* value )
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 int ival = 0;
611 if ( ToInt( str, &ival )) {
612 *value = (ival==0) ? false : true;
613 return true;
614 }
615 if ( StringEqual( str, "true" ) ) {
616 *value = true;
617 return true;
618 }
619 else if ( StringEqual( str, "false" ) ) {
620 *value = false;
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
627bool XMLUtil::ToFloat( const char* str, float* value )
628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
630 return true;
631 }
632 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700633}
634
Lee Thomason51c12712016-06-04 20:18:49 -0700635
Lee Thomason21be8822012-07-15 17:27:22 -0700636bool XMLUtil::ToDouble( const char* str, double* value )
637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
639 return true;
640 }
641 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700642}
643
644
Lee Thomason51c12712016-06-04 20:18:49 -0700645bool XMLUtil::ToInt64(const char* str, int64_t* value)
646{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700647 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
648 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
649 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700650 return true;
651 }
652 return false;
653}
654
655
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700656char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657{
Dmitry-Me02384662015-03-03 16:02:13 +0300658 TIXMLASSERT( node );
659 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400660 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000661 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000662 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300663 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300664 *node = 0;
665 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 return p;
667 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Dmitry-Me962083b2015-05-26 11:38:30 +0300669 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 static const char* xmlHeader = { "<?" };
671 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300673 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 static const int xmlHeaderLen = 2;
677 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300679 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
683 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400684 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += xmlHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000692 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += commentHeaderLen;
694 }
695 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300696 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000698 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p += cdataHeaderLen;
700 text->SetCData( true );
701 }
702 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += dtdHeaderLen;
706 }
707 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += elementHeaderLen;
711 }
712 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000716 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718
Dmitry-Me02384662015-03-03 16:02:13 +0300719 TIXMLASSERT( returnNode );
720 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 *node = returnNode;
722 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723}
724
725
Lee Thomason751da522012-02-10 08:50:51 -0800726bool XMLDocument::Accept( XMLVisitor* visitor ) const
727{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300728 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 if ( visitor->VisitEnter( *this ) ) {
730 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
731 if ( !node->Accept( visitor ) ) {
732 break;
733 }
734 }
735 }
736 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800737}
Lee Thomason56bdd022012-02-09 18:16:58 -0800738
739
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740// --------- XMLNode ----------- //
741
742XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 _document( doc ),
744 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200745 _value(),
kezenatorec694152016-11-26 17:21:43 +1000746 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200748 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700749 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200750 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800752}
753
754
755XMLNode::~XMLNode()
756{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 if ( _parent ) {
759 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800761}
762
Gumichan010f1fa6d2018-02-01 14:16:24 +0100763const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200764{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300765 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530766 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530767 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200768 return _value.GetStr();
769}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800770
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800771void XMLNode::SetValue( const char* str, bool staticMem )
772{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 }
776 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800779}
780
Dmitry-Me3f63f212017-06-19 18:25:19 +0300781XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700782{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300783 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700784 if (!clone) return 0;
785
786 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300787 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700788 TIXMLASSERT(childClone);
789 clone->InsertEndChild(childClone);
790 }
791 return clone;
792}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800794void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800795{
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300797 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300798 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800801}
802
803
804void XMLNode::Unlink( XMLNode* child )
805{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300806 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300807 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300808 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( child == _firstChild ) {
810 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( child == _lastChild ) {
813 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomasond923c672012-01-23 08:44:25 -0800815
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( child->_prev ) {
817 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 if ( child->_next ) {
820 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason8a763612017-06-16 09:30:16 -0700822 child->_next = 0;
823 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700824 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800825}
826
827
U-Stream\Leeae25a442012-02-17 17:48:16 -0800828void XMLNode::DeleteChild( XMLNode* node )
829{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300830 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300831 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100833 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700834 TIXMLASSERT(node->_prev == 0);
835 TIXMLASSERT(node->_next == 0);
836 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400837 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800838}
839
840
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800841XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
842{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300843 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300844 if ( addThis->_document != _document ) {
845 TIXMLASSERT( false );
846 return 0;
847 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800848 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 if ( _lastChild ) {
851 TIXMLASSERT( _firstChild );
852 TIXMLASSERT( _lastChild->_next == 0 );
853 _lastChild->_next = addThis;
854 addThis->_prev = _lastChild;
855 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 TIXMLASSERT( _firstChild == 0 );
861 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800862
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 addThis->_prev = 0;
864 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800868}
869
870
Lee Thomason1ff38e02012-02-14 18:18:16 -0800871XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
872{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300873 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 if ( addThis->_document != _document ) {
875 TIXMLASSERT( false );
876 return 0;
877 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800878 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700879
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 if ( _firstChild ) {
881 TIXMLASSERT( _lastChild );
882 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800883
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 _firstChild->_prev = addThis;
885 addThis->_next = _firstChild;
886 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 TIXMLASSERT( _lastChild == 0 );
892 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 addThis->_prev = 0;
895 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700897 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400898 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800899}
900
901
902XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
903{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300904 TIXMLASSERT( addThis );
905 if ( addThis->_document != _document ) {
906 TIXMLASSERT( false );
907 return 0;
908 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700909
Dmitry-Meabb2d042014-12-09 12:59:31 +0300910 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700911
Lee Thomason624d43f2012-10-12 10:58:48 -0700912 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300913 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 return 0;
915 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300916 if ( afterThis == addThis ) {
917 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
918 // Now AddThis must disappear from it's location and then
919 // reappear between BeforeThis and OneAfterAddThis.
920 // So just leave it where it is.
921 return addThis;
922 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800923
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 // The last node or the only node.
926 return InsertEndChild( addThis );
927 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800928 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 addThis->_prev = afterThis;
930 addThis->_next = afterThis->_next;
931 afterThis->_next->_prev = addThis;
932 afterThis->_next = addThis;
933 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800935}
936
937
938
939
Dmitry-Me886ad972015-07-22 11:00:51 +0300940const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800941{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300942 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300943 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300945 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 }
948 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800949}
950
951
Dmitry-Me886ad972015-07-22 11:00:51 +0300952const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800953{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300954 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300955 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300957 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 }
960 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800961}
962
963
Dmitry-Me886ad972015-07-22 11:00:51 +0300964const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300966 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 const XMLElement* element = node->ToElementWithName( name );
968 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400969 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 }
972 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973}
974
975
Dmitry-Me886ad972015-07-22 11:00:51 +0300976const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800977{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300978 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300979 const XMLElement* element = node->ToElementWithName( name );
980 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400981 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 }
984 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300988char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 // This is a recursive method, but thinking about it "at the current level"
991 // it is a pretty simple flat list:
992 // <foo/>
993 // <!-- comment -->
994 //
995 // With a special case:
996 // <foo>
997 // </foo>
998 // <!-- comment -->
999 //
1000 // Where the closing element (/foo) *must* be the next thing after the opening
1001 // element, and the names must match. BUT the tricky bit is that the closing
1002 // element will be read by the child.
1003 //
1004 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1005 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006
Lee Thomasond946dda2018-04-05 09:11:08 -07001007 XMLDocument::DepthTracker tracker(_document);
1008 if (_document->Error())
1009 return 0;
1010
1011 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001013
Lee Thomason624d43f2012-10-12 10:58:48 -07001014 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001015 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001016 if ( node == 0 ) {
1017 break;
1018 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001019
kezenatore3531812016-11-29 19:49:07 +10001020 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001021
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001023 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001025 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001026 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001027 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 }
1029 break;
1030 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001031
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301032 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301033 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001034 // Declarations are only allowed at document level
1035 bool wellLocated = ( ToDocument() != 0 );
1036 if ( wellLocated ) {
1037 // Multiple declarations are allowed but all declarations
1038 // must occur before anything else
1039 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1040 if ( !existingNode->ToDeclaration() ) {
1041 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301042 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001043 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301044 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001045 }
1046 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001047 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001048 DeleteNode( node );
1049 break;
1050 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301051 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301052
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001053 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001055 // We read the end tag. Return it to the parent.
1056 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001057 if ( parentEndTag ) {
1058 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001059 }
1060 node->_memPool->SetTracked(); // created and then immediately deleted.
1061 DeleteNode( node );
1062 return p;
1063 }
1064
1065 // Handle an end tag returned to this level.
1066 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001067 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001068 if ( endTag.Empty() ) {
1069 if ( ele->ClosingType() == XMLElement::OPEN ) {
1070 mismatch = true;
1071 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001073 else {
1074 if ( ele->ClosingType() != XMLElement::OPEN ) {
1075 mismatch = true;
1076 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001077 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001078 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 }
1080 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001081 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001082 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001083 DeleteNode( node );
1084 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001085 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 }
JayXondbfdd8f2014-12-12 20:07:14 -05001087 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 }
1089 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001090}
1091
Lee Thomason816d3fa2017-06-05 14:35:55 -07001092/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001093{
1094 if ( node == 0 ) {
1095 return;
1096 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001097 TIXMLASSERT(node->_document);
1098 if (!node->ToDocument()) {
1099 node->_document->MarkInUse(node);
1100 }
1101
Dmitry-Mee3225b12014-09-03 11:03:11 +04001102 MemPool* pool = node->_memPool;
1103 node->~XMLNode();
1104 pool->Free( node );
1105}
1106
Lee Thomason3cebdc42015-01-05 17:16:28 -08001107void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001108{
1109 TIXMLASSERT( insertThis );
1110 TIXMLASSERT( insertThis->_document == _document );
1111
Lee Thomason816d3fa2017-06-05 14:35:55 -07001112 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001113 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001114 }
1115 else {
1116 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001117 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001118 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001119}
1120
Dmitry-Meecb9b072016-10-12 16:44:59 +03001121const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1122{
1123 const XMLElement* element = this->ToElement();
1124 if ( element == 0 ) {
1125 return 0;
1126 }
1127 if ( name == 0 ) {
1128 return element;
1129 }
1130 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1131 return element;
1132 }
1133 return 0;
1134}
1135
Lee Thomason5492a1c2012-01-23 15:32:10 -08001136// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001137char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001140 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001142 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 }
1144 return p;
1145 }
1146 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001147 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1148 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001149 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001151
kezenator4f756162016-11-29 19:46:27 +10001152 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( p && *p ) {
1154 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001155 }
1156 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001157 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 }
1159 }
1160 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001161}
1162
1163
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001164XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 }
1169 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1170 text->SetCData( this->CData() );
1171 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172}
1173
1174
1175bool XMLText::ShallowEqual( const XMLNode* compare ) const
1176{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001177 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001178 const XMLText* text = compare->ToText();
1179 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001180}
1181
1182
Lee Thomason56bdd022012-02-09 18:16:58 -08001183bool XMLText::Accept( XMLVisitor* visitor ) const
1184{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001185 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001187}
1188
1189
Lee Thomason3f57d272012-01-11 15:30:03 -08001190// --------- XMLComment ---------- //
1191
Lee Thomasone4422302012-01-20 17:59:50 -08001192XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001193{
1194}
1195
1196
Lee Thomasonce0763e2012-01-11 15:43:54 -08001197XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001198{
Lee Thomason3f57d272012-01-11 15:30:03 -08001199}
1200
1201
kezenator4f756162016-11-29 19:46:27 +10001202char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001205 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001207 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 }
1209 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001210}
1211
1212
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
1218 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1219 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001220}
1221
1222
1223bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1224{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001225 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001226 const XMLComment* comment = compare->ToComment();
1227 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001228}
1229
1230
Lee Thomason751da522012-02-10 08:50:51 -08001231bool XMLComment::Accept( XMLVisitor* visitor ) const
1232{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001233 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001235}
Lee Thomason56bdd022012-02-09 18:16:58 -08001236
1237
Lee Thomason50f97b22012-02-11 16:33:40 -08001238// --------- XMLDeclaration ---------- //
1239
1240XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1241{
1242}
1243
1244
1245XMLDeclaration::~XMLDeclaration()
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001248}
1249
1250
kezenator4f756162016-11-29 19:46:27 +10001251char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001254 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001256 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 }
1258 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001259}
1260
1261
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001262XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001265 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 }
1267 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1268 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001269}
1270
1271
1272bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1273{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001274 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001275 const XMLDeclaration* declaration = compare->ToDeclaration();
1276 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001277}
1278
1279
1280
Lee Thomason50f97b22012-02-11 16:33:40 -08001281bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1282{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001283 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001285}
1286
1287// --------- XMLUnknown ---------- //
1288
1289XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1290{
1291}
1292
1293
1294XMLUnknown::~XMLUnknown()
1295{
1296}
1297
1298
kezenator4f756162016-11-29 19:46:27 +10001299char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001302 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001304 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 }
1306 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001307}
1308
1309
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001310XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1316 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001317}
1318
1319
1320bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1321{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001322 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001323 const XMLUnknown* unknown = compare->ToUnknown();
1324 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001325}
1326
1327
Lee Thomason50f97b22012-02-11 16:33:40 -08001328bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1329{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001330 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001332}
1333
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001335
Gumichan010f1fa6d2018-02-01 14:16:24 +01001336const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001337{
1338 return _name.GetStr();
1339}
1340
Gumichan010f1fa6d2018-02-01 14:16:24 +01001341const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001342{
1343 return _value.GetStr();
1344}
1345
kezenator4f756162016-11-29 19:46:27 +10001346char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( !p || !*p ) {
1351 return 0;
1352 }
Lee Thomason22aead12012-01-23 13:29:35 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001355 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001356 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return 0;
1358 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001359
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001361 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( *p != '\"' && *p != '\'' ) {
1363 return 0;
1364 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001365
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 char endTag[2] = { *p, 0 };
1367 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001368
kezenator4f756162016-11-29 19:46:27 +10001369 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371}
1372
1373
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001374void XMLAttribute::SetName( const char* n )
1375{
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001377}
1378
1379
Lee Thomason2fa81722012-11-09 12:37:46 -08001380XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001383 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
1385 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason2fa81722012-11-09 12:37:46 -08001389XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001392 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001395}
1396
1397
Lee Thomason51c12712016-06-04 20:18:49 -07001398XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1399{
1400 if (XMLUtil::ToInt64(Value(), value)) {
1401 return XML_SUCCESS;
1402 }
1403 return XML_WRONG_ATTRIBUTE_TYPE;
1404}
1405
1406
Lee Thomason2fa81722012-11-09 12:37:46 -08001407XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001410 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 }
1412 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413}
1414
1415
Lee Thomason2fa81722012-11-09 12:37:46 -08001416XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001419 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
Lee Thomason2fa81722012-11-09 12:37:46 -08001425XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001428 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 }
1430 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001431}
1432
1433
1434void XMLAttribute::SetAttribute( const char* v )
1435{
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437}
1438
1439
Lee Thomason1ff38e02012-02-14 18:18:16 -08001440void XMLAttribute::SetAttribute( int v )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001445}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446
1447
1448void XMLAttribute::SetAttribute( unsigned v )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453}
1454
1455
Lee Thomason51c12712016-06-04 20:18:49 -07001456void XMLAttribute::SetAttribute(int64_t v)
1457{
1458 char buf[BUF_SIZE];
1459 XMLUtil::ToStr(v, buf, BUF_SIZE);
1460 _value.SetStr(buf);
1461}
1462
1463
1464
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465void XMLAttribute::SetAttribute( bool v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472void XMLAttribute::SetAttribute( double v )
1473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
1479void XMLAttribute::SetAttribute( float v )
1480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 char buf[BUF_SIZE];
1482 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001484}
1485
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001486
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001487// --------- XMLElement ---------- //
1488XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001489 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491{
1492}
1493
1494
1495XMLElement::~XMLElement()
1496{
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 while( _rootAttribute ) {
1498 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001499 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001502}
1503
1504
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1506{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001507 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1509 return a;
1510 }
1511 }
1512 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001513}
1514
1515
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001516const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 const XMLAttribute* a = FindAttribute( name );
1519 if ( !a ) {
1520 return 0;
1521 }
1522 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1523 return a->Value();
1524 }
1525 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001526}
1527
Gumichan010f1fa6d2018-02-01 14:16:24 +01001528int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001529{
1530 int i = defaultValue;
1531 QueryIntAttribute(name, &i);
1532 return i;
1533}
1534
Gumichan010f1fa6d2018-02-01 14:16:24 +01001535unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001536{
1537 unsigned i = defaultValue;
1538 QueryUnsignedAttribute(name, &i);
1539 return i;
1540}
1541
Gumichan010f1fa6d2018-02-01 14:16:24 +01001542int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001543{
1544 int64_t i = defaultValue;
1545 QueryInt64Attribute(name, &i);
1546 return i;
1547}
1548
Gumichan010f1fa6d2018-02-01 14:16:24 +01001549bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001550{
1551 bool b = defaultValue;
1552 QueryBoolAttribute(name, &b);
1553 return b;
1554}
1555
Gumichan010f1fa6d2018-02-01 14:16:24 +01001556double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001557{
1558 double d = defaultValue;
1559 QueryDoubleAttribute(name, &d);
1560 return d;
1561}
1562
Gumichan010f1fa6d2018-02-01 14:16:24 +01001563float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001564{
1565 float f = defaultValue;
1566 QueryFloatAttribute(name, &f);
1567 return f;
1568}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001569
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001570const char* XMLElement::GetText() const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001573 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576}
1577
1578
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001579void XMLElement::SetText( const char* inText )
1580{
Uli Kusterer869bb592014-01-21 01:36:16 +01001581 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001582 FirstChild()->SetValue( inText );
1583 else {
1584 XMLText* theText = GetDocument()->NewText( inText );
1585 InsertFirstChild( theText );
1586 }
1587}
1588
Lee Thomason5bb2d802014-01-24 10:42:57 -08001589
Gumichan010f1fa6d2018-02-01 14:16:24 +01001590void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
Gumichan010f1fa6d2018-02-01 14:16:24 +01001598void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr( v, buf, BUF_SIZE );
1602 SetText( buf );
1603}
1604
1605
Lee Thomason51c12712016-06-04 20:18:49 -07001606void XMLElement::SetText(int64_t v)
1607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr(v, buf, BUF_SIZE);
1610 SetText(buf);
1611}
1612
1613
1614void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001615{
1616 char buf[BUF_SIZE];
1617 XMLUtil::ToStr( v, buf, BUF_SIZE );
1618 SetText( buf );
1619}
1620
1621
Gumichan010f1fa6d2018-02-01 14:16:24 +01001622void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001623{
1624 char buf[BUF_SIZE];
1625 XMLUtil::ToStr( v, buf, BUF_SIZE );
1626 SetText( buf );
1627}
1628
1629
Gumichan010f1fa6d2018-02-01 14:16:24 +01001630void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001631{
1632 char buf[BUF_SIZE];
1633 XMLUtil::ToStr( v, buf, BUF_SIZE );
1634 SetText( buf );
1635}
1636
1637
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001641 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001642 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
Lee Thomason51c12712016-06-04 20:18:49 -07001664XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1665{
1666 if (FirstChild() && FirstChild()->ToText()) {
1667 const char* t = FirstChild()->Value();
1668 if (XMLUtil::ToInt64(t, ival)) {
1669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
1674}
1675
1676
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001680 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001681 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 return XML_SUCCESS;
1683 }
1684 return XML_CAN_NOT_CONVERT_TEXT;
1685 }
1686 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001687}
1688
1689
MortenMacFly4ee49f12013-01-14 20:03:14 +01001690XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001693 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001694 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 return XML_SUCCESS;
1696 }
1697 return XML_CAN_NOT_CONVERT_TEXT;
1698 }
1699 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001700}
1701
1702
MortenMacFly4ee49f12013-01-14 20:03:14 +01001703XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001706 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001707 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 return XML_SUCCESS;
1709 }
1710 return XML_CAN_NOT_CONVERT_TEXT;
1711 }
1712 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001713}
1714
Josh Wittnercf3dd092016-10-11 18:57:17 -07001715int XMLElement::IntText(int defaultValue) const
1716{
1717 int i = defaultValue;
1718 QueryIntText(&i);
1719 return i;
1720}
1721
1722unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1723{
1724 unsigned i = defaultValue;
1725 QueryUnsignedText(&i);
1726 return i;
1727}
1728
1729int64_t XMLElement::Int64Text(int64_t defaultValue) const
1730{
1731 int64_t i = defaultValue;
1732 QueryInt64Text(&i);
1733 return i;
1734}
1735
1736bool XMLElement::BoolText(bool defaultValue) const
1737{
1738 bool b = defaultValue;
1739 QueryBoolText(&b);
1740 return b;
1741}
1742
1743double XMLElement::DoubleText(double defaultValue) const
1744{
1745 double d = defaultValue;
1746 QueryDoubleText(&d);
1747 return d;
1748}
1749
1750float XMLElement::FloatText(float defaultValue) const
1751{
1752 float f = defaultValue;
1753 QueryFloatText(&f);
1754 return f;
1755}
Lee Thomason21be8822012-07-15 17:27:22 -07001756
1757
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001758XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1759{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 XMLAttribute* last = 0;
1761 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1766 break;
1767 }
1768 }
1769 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001770 attrib = CreateAttribute();
1771 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001773 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001777 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 attrib->SetName( name );
1781 }
1782 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001783}
1784
1785
U-Stream\Leeae25a442012-02-17 17:48:16 -08001786void XMLElement::DeleteAttribute( const char* name )
1787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1791 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001797 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 break;
1799 }
1800 prev = a;
1801 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001802}
1803
1804
kezenator4f756162016-11-29 19:46:27 +10001805char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001808
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 // Read the attributes.
1810 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001811 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001812 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001813 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 return 0;
1815 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001816
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001818 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001819 XMLAttribute* attrib = CreateAttribute();
1820 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001821 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001822
kezenatorec694152016-11-26 17:21:43 +10001823 int attrLineNum = attrib->_parseLineNum;
1824
kezenator4f756162016-11-29 19:46:27 +10001825 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001827 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001828 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 return 0;
1830 }
1831 // There is a minor bug here: if the attribute in the source xml
1832 // document is duplicated, it will not be detected and the
1833 // attribute will be doubly added. However, tracking the 'prevAttribute'
1834 // avoids re-scanning the attribute list. Preferring performance for
1835 // now, may reconsider in the future.
1836 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001837 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001841 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 }
1844 prevAttribute = attrib;
1845 }
1846 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 else if ( *p == '>' ) {
1848 ++p;
1849 break;
1850 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001851 // end of the tag
1852 else if ( *p == '/' && *(p+1) == '>' ) {
1853 _closingType = CLOSED;
1854 return p+2; // done; sealed element.
1855 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001857 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 return 0;
1859 }
1860 }
1861 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001862}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001863
Dmitry-Mee3225b12014-09-03 11:03:11 +04001864void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1865{
1866 if ( attribute == 0 ) {
1867 return;
1868 }
1869 MemPool* pool = attribute->_memPool;
1870 attribute->~XMLAttribute();
1871 pool->Free( attribute );
1872}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001873
Dmitry-Mea60caa22016-11-22 18:28:08 +03001874XMLAttribute* XMLElement::CreateAttribute()
1875{
1876 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1877 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001878 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001879 attrib->_memPool = &_document->_attributePool;
1880 attrib->_memPool->SetTracked();
1881 return attrib;
1882}
1883
Lee Thomason67d61312012-01-24 16:01:51 -08001884//
1885// <ele></ele>
1886// <ele>foo<b>bar</b></ele>
1887//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001888char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001892
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 // The closing element is the </element> form. It is
1894 // parsed just like a regular element then deleted from
1895 // the DOM.
1896 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 ++p;
1899 }
Lee Thomason67d61312012-01-24 16:01:51 -08001900
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 p = _value.ParseName( p );
1902 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 return 0;
1904 }
Lee Thomason67d61312012-01-24 16:01:51 -08001905
kezenator4f756162016-11-29 19:46:27 +10001906 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001907 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 return p;
1909 }
Lee Thomason67d61312012-01-24 16:01:51 -08001910
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001911 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001913}
1914
1915
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916
1917XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 }
1922 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1923 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1924 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1925 }
1926 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927}
1928
1929
1930bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1931{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001932 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001934 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001935
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 const XMLAttribute* a=FirstAttribute();
1937 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001938
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 while ( a && b ) {
1940 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1941 return false;
1942 }
1943 a = a->Next();
1944 b = b->Next();
1945 }
1946 if ( a || b ) {
1947 // different count
1948 return false;
1949 }
1950 return true;
1951 }
1952 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001953}
1954
1955
Lee Thomason751da522012-02-10 08:50:51 -08001956bool XMLElement::Accept( XMLVisitor* visitor ) const
1957{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001958 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1961 if ( !node->Accept( visitor ) ) {
1962 break;
1963 }
1964 }
1965 }
1966 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001967}
Lee Thomason56bdd022012-02-09 18:16:58 -08001968
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001969
Lee Thomason3f57d272012-01-11 15:30:03 -08001970// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001971
1972// Warning: List must match 'enum XMLError'
1973const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1974 "XML_SUCCESS",
1975 "XML_NO_ATTRIBUTE",
1976 "XML_WRONG_ATTRIBUTE_TYPE",
1977 "XML_ERROR_FILE_NOT_FOUND",
1978 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1979 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001980 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001981 "XML_ERROR_PARSING_ELEMENT",
1982 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001983 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001984 "XML_ERROR_PARSING_TEXT",
1985 "XML_ERROR_PARSING_CDATA",
1986 "XML_ERROR_PARSING_COMMENT",
1987 "XML_ERROR_PARSING_DECLARATION",
1988 "XML_ERROR_PARSING_UNKNOWN",
1989 "XML_ERROR_EMPTY_DOCUMENT",
1990 "XML_ERROR_MISMATCHED_ELEMENT",
1991 "XML_ERROR_PARSING",
1992 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07001993 "XML_NO_TEXT_NODE",
1994 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07001995};
1996
1997
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001998XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _writeBOM( false ),
2001 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002002 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002003 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002004 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002005 _errorLineNum( 0 ),
2006 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002007 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002008 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002009 _unlinked(),
2010 _elementPool(),
2011 _attributePool(),
2012 _textPool(),
2013 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002014{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002015 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2016 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002017}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002018
2019
Lee Thomason3f57d272012-01-11 15:30:03 -08002020XMLDocument::~XMLDocument()
2021{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002022 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002023}
2024
2025
Lee Thomason816d3fa2017-06-05 14:35:55 -07002026void XMLDocument::MarkInUse(XMLNode* node)
2027{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002028 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002029 TIXMLASSERT(node->_parent == 0);
2030
2031 for (int i = 0; i < _unlinked.Size(); ++i) {
2032 if (node == _unlinked[i]) {
2033 _unlinked.SwapRemove(i);
2034 break;
2035 }
2036 }
2037}
2038
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002039void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002040{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002041 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002042 while( _unlinked.Size()) {
2043 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2044 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002045
Peter Matula50689912018-01-09 12:52:26 +01002046#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002047 const bool hadError = Error();
2048#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002049 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002050
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 delete [] _charBuffer;
2052 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002053 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002054
2055#if 0
2056 _textPool.Trace( "text" );
2057 _elementPool.Trace( "element" );
2058 _commentPool.Trace( "comment" );
2059 _attributePool.Trace( "attribute" );
2060#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002061
Peter Matula50689912018-01-09 12:52:26 +01002062#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002063 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002064 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2065 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2066 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2067 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2068 }
2069#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002070}
2071
Lee Thomason3f57d272012-01-11 15:30:03 -08002072
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002073void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002074{
2075 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002076 if (target == this) {
2077 return; // technically success - a no-op.
2078 }
Lee Thomason7085f002017-06-01 18:09:43 -07002079
2080 target->Clear();
2081 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2082 target->InsertEndChild(node->DeepClone(target));
2083 }
2084}
2085
Lee Thomason2c85a712012-01-31 08:24:24 -08002086XMLElement* XMLDocument::NewElement( const char* name )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 ele->SetName( name );
2090 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002091}
2092
2093
Lee Thomason1ff38e02012-02-14 18:18:16 -08002094XMLComment* XMLDocument::NewComment( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 comment->SetValue( str );
2098 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002099}
2100
2101
2102XMLText* XMLDocument::NewText( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 text->SetValue( str );
2106 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002107}
2108
2109
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002110XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2114 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
2117
2118XMLUnknown* XMLDocument::NewUnknown( const char* str )
2119{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002120 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 unk->SetValue( str );
2122 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002123}
2124
Dmitry-Me01578db2014-08-19 10:18:48 +04002125static FILE* callfopen( const char* filepath, const char* mode )
2126{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002127 TIXMLASSERT( filepath );
2128 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002129#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2130 FILE* fp = 0;
2131 errno_t err = fopen_s( &fp, filepath, mode );
2132 if ( err ) {
2133 return 0;
2134 }
2135#else
2136 FILE* fp = fopen( filepath, mode );
2137#endif
2138 return fp;
2139}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002140
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002141void XMLDocument::DeleteNode( XMLNode* node ) {
2142 TIXMLASSERT( node );
2143 TIXMLASSERT(node->_document == this );
2144 if (node->_parent) {
2145 node->_parent->DeleteChild( node );
2146 }
2147 else {
2148 // Isn't in the tree.
2149 // Use the parent delete.
2150 // Also, we need to mark it tracked: we 'know'
2151 // it was never used.
2152 node->_memPool->SetTracked();
2153 // Call the static XMLNode version:
2154 XMLNode::DeleteNode(node);
2155 }
2156}
2157
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002158
Lee Thomason2fa81722012-11-09 12:37:46 -08002159XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002160{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002161 if ( !filename ) {
2162 TIXMLASSERT( false );
2163 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2164 return _errorID;
2165 }
2166
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002167 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002168 FILE* fp = callfopen( filename, "rb" );
2169 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002170 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 }
2173 LoadFile( fp );
2174 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002176}
2177
Dmitry-Me901fed52015-09-25 10:29:51 +03002178// This is likely overengineered template art to have a check that unsigned long value incremented
2179// by one still fits into size_t. If size_t type is larger than unsigned long type
2180// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2181// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2182// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2183// types sizes relate to each other.
2184template
2185<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2186struct LongFitsIntoSizeTMinusOne {
2187 static bool Fits( unsigned long value )
2188 {
2189 return value < (size_t)-1;
2190 }
2191};
2192
2193template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002194struct LongFitsIntoSizeTMinusOne<false> {
2195 static bool Fits( unsigned long )
2196 {
2197 return true;
2198 }
2199};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002200
Lee Thomason2fa81722012-11-09 12:37:46 -08002201XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002202{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002203 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002204
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002205 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002206 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002207 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002208 return _errorID;
2209 }
2210
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002212 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002214 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002215 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002216 return _errorID;
2217 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002218 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002219
Dmitry-Me901fed52015-09-25 10:29:51 +03002220 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002221 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002222 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002223 return _errorID;
2224 }
2225
Dmitry-Me72801b82015-05-07 09:41:39 +03002226 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002227 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002230
Dmitry-Me72801b82015-05-07 09:41:39 +03002231 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002232 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _charBuffer = new char[size+1];
2234 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002236 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002239
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241
Dmitry-Me97476b72015-01-01 16:15:57 +03002242 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244}
2245
2246
Lee Thomason2fa81722012-11-09 12:37:46 -08002247XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002249 if ( !filename ) {
2250 TIXMLASSERT( false );
2251 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2252 return _errorID;
2253 }
2254
Dmitry-Me01578db2014-08-19 10:18:48 +04002255 FILE* fp = callfopen( filename, "w" );
2256 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002257 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 }
2260 SaveFile(fp, compact);
2261 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002262 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002263}
2264
2265
Lee Thomason2fa81722012-11-09 12:37:46 -08002266XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002267{
Ant Mitchell189198f2015-03-24 16:20:36 +00002268 // Clear any error from the last save, otherwise it will get reported
2269 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002270 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 XMLPrinter stream( fp, compact );
2272 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002273 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002274}
2275
Lee Thomason1ff38e02012-02-14 18:18:16 -08002276
Lee Thomason2fa81722012-11-09 12:37:46 -08002277XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002278{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002279 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002280
Lee Thomason82d32002014-02-21 22:47:18 -08002281 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002282 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 }
2285 if ( len == (size_t)(-1) ) {
2286 len = strlen( p );
2287 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002288 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 _charBuffer = new char[ len+1 ];
2290 memcpy( _charBuffer, p, len );
2291 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002292
Dmitry-Me97476b72015-01-01 16:15:57 +03002293 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002294 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002295 // clean up now essentially dangling memory.
2296 // and the parse fail can put objects in the
2297 // pools that are dead and inaccessible.
2298 DeleteChildren();
2299 _elementPool.Clear();
2300 _attributePool.Clear();
2301 _textPool.Clear();
2302 _commentPool.Clear();
2303 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002305}
2306
2307
PKEuS1c5f99e2013-07-06 11:28:39 +02002308void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002309{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002310 if ( streamer ) {
2311 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002313 else {
2314 XMLPrinter stdoutStreamer( stdout );
2315 Accept( &stdoutStreamer );
2316 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002317}
2318
2319
Lee Thomasonaa188392017-09-19 17:54:31 -07002320void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002321{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002322 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002323 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002324 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002325 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002326
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002327 size_t BUFFER_SIZE = 1000;
2328 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002329
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002330 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 -07002331
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002332 if (format) {
2333 size_t len = strlen(buffer);
2334 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2335 len = strlen(buffer);
2336
2337 va_list va;
2338 va_start(va, format);
2339 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2340 va_end(va);
2341 }
2342 _errorStr.SetStr(buffer);
2343 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002344}
2345
Lee Thomasonaa188392017-09-19 17:54:31 -07002346
Lee Thomasone90e9012016-12-24 07:34:39 -08002347/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002348{
kezenator5a700712016-11-26 13:54:42 +10002349 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2350 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002351 TIXMLASSERT( errorName && errorName[0] );
2352 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002353}
Lee Thomason5cae8972012-01-24 18:03:07 -08002354
Gumichan010f1fa6d2018-02-01 14:16:24 +01002355const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002356{
Lee Thomasonaa188392017-09-19 17:54:31 -07002357 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002358}
2359
Lee Thomasonf49b9652017-10-11 10:57:49 -07002360
2361void XMLDocument::PrintError() const
2362{
2363 printf("%s\n", ErrorStr());
2364}
2365
kezenator5a700712016-11-26 13:54:42 +10002366const char* XMLDocument::ErrorName() const
2367{
Lee Thomasone90e9012016-12-24 07:34:39 -08002368 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002369}
2370
Dmitry-Me97476b72015-01-01 16:15:57 +03002371void XMLDocument::Parse()
2372{
2373 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2374 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002375 _parseCurLineNum = 1;
2376 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002377 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002378 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002379 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002380 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002381 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002382 return;
2383 }
kezenator4f756162016-11-29 19:46:27 +10002384 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002385}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002386
Lee Thomasond946dda2018-04-05 09:11:08 -07002387bool XMLDocument::PushDepth()
2388{
2389 _parsingDepth++;
2390 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2391 SetError(XMLError::XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2392 return false;
2393 }
2394 return true;
2395}
2396
2397bool XMLDocument::PopDepth()
2398{
2399 TIXMLASSERT(_parsingDepth > 0);
2400 --_parsingDepth;
2401 return true;
2402}
2403
PKEuS1bfb9542013-08-04 13:51:17 +02002404XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002405 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002406 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002407 _firstElement( true ),
2408 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002409 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002410 _textDepth( -1 ),
2411 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002412 _compactMode( compact ),
2413 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002415 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002416 _entityFlag[i] = false;
2417 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
2419 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002420 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002421 const unsigned char flagIndex = (unsigned char)entityValue;
2422 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2423 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002425 _restrictedEntityFlag[(unsigned char)'&'] = true;
2426 _restrictedEntityFlag[(unsigned char)'<'] = true;
2427 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002428 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002429}
2430
2431
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002432void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002433{
2434 va_list va;
2435 va_start( va, format );
2436
Lee Thomason624d43f2012-10-12 10:58:48 -07002437 if ( _fp ) {
2438 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 }
2440 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002441 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 // Close out and re-start the va-args
2443 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002444 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002446 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002447 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002448 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002449 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002450 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002451}
2452
2453
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002454void XMLPrinter::Write( const char* data, size_t size )
2455{
2456 if ( _fp ) {
2457 fwrite ( data , sizeof(char), size, _fp);
2458 }
2459 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002460 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002461 memcpy( p, data, size );
2462 p[size] = 0;
2463 }
2464}
2465
2466
2467void XMLPrinter::Putc( char ch )
2468{
2469 if ( _fp ) {
2470 fputc ( ch, _fp);
2471 }
2472 else {
2473 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2474 p[0] = ch;
2475 p[1] = 0;
2476 }
2477}
2478
2479
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002480void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002483 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002484 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002485}
2486
2487
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002488void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 // Look for runs of bytes between entities to print.
2491 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002492
Lee Thomason624d43f2012-10-12 10:58:48 -07002493 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002494 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002496 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002497 // Remember, char is sometimes signed. (How many times has that bitten me?)
2498 if ( *q > 0 && *q < ENTITY_RANGE ) {
2499 // Check for entities. If one is found, flush
2500 // the stream up until the entity, write the
2501 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002502 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002504 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002505 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002506 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002507 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002509 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002510 for( int i=0; i<NUM_ENTITIES; ++i ) {
2511 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002512 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002513 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002514 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002515 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 break;
2517 }
2518 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002519 if ( !entityPatternPrinted ) {
2520 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2521 TIXMLASSERT( false );
2522 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 ++p;
2524 }
2525 }
2526 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002527 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 }
2529 }
2530 // Flush the remaining string. This will be the entire
2531 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002532 TIXMLASSERT( p <= q );
2533 if ( !_processEntities || ( p < q ) ) {
Brad Anderson85aac022017-10-24 21:48:28 -06002534 const size_t delta = q - p;
2535 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2536 Write( p, toPrint );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002537 }
Lee Thomason857b8682012-01-25 17:50:25 -08002538}
2539
U-Stream\Leeae25a442012-02-17 17:48:16 -08002540
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002541void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002543 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002544 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 +03002545 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 }
2547 if ( writeDec ) {
2548 PushDeclaration( "xml version=\"1.0\"" );
2549 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002550}
2551
2552
Uli Kusterer593a33d2014-02-01 12:48:51 +01002553void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002554{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002555 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002556 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002557
Uli Kusterer593a33d2014-02-01 12:48:51 +01002558 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002559 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002560 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002561 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002562 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002563 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002564
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002565 Write ( "<" );
2566 Write ( name );
2567
Lee Thomason624d43f2012-10-12 10:58:48 -07002568 _elementJustOpened = true;
2569 _firstElement = false;
2570 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002571}
2572
2573
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002574void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002575{
Lee Thomason624d43f2012-10-12 10:58:48 -07002576 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002577 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002578 Write( name );
2579 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002580 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002581 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002582}
2583
2584
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002585void XMLPrinter::PushAttribute( const char* name, int v )
2586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002587 char buf[BUF_SIZE];
2588 XMLUtil::ToStr( v, buf, BUF_SIZE );
2589 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002590}
2591
2592
2593void XMLPrinter::PushAttribute( const char* name, unsigned v )
2594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 char buf[BUF_SIZE];
2596 XMLUtil::ToStr( v, buf, BUF_SIZE );
2597 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002598}
2599
2600
Lee Thomason51c12712016-06-04 20:18:49 -07002601void XMLPrinter::PushAttribute(const char* name, int64_t v)
2602{
2603 char buf[BUF_SIZE];
2604 XMLUtil::ToStr(v, buf, BUF_SIZE);
2605 PushAttribute(name, buf);
2606}
2607
2608
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002609void XMLPrinter::PushAttribute( const char* name, bool v )
2610{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 char buf[BUF_SIZE];
2612 XMLUtil::ToStr( v, buf, BUF_SIZE );
2613 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002614}
2615
2616
2617void XMLPrinter::PushAttribute( const char* name, double v )
2618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 char buf[BUF_SIZE];
2620 XMLUtil::ToStr( v, buf, BUF_SIZE );
2621 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002622}
2623
2624
Uli Kustererca412e82014-02-01 13:35:05 +01002625void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002626{
Lee Thomason624d43f2012-10-12 10:58:48 -07002627 --_depth;
2628 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002629
Lee Thomason624d43f2012-10-12 10:58:48 -07002630 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002631 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 }
2633 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002634 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002635 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002636 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002637 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002638 Write ( "</" );
2639 Write ( name );
2640 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002641 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002642
Lee Thomason624d43f2012-10-12 10:58:48 -07002643 if ( _textDepth == _depth ) {
2644 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002645 }
Uli Kustererca412e82014-02-01 13:35:05 +01002646 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002647 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002648 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002649 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002650}
2651
2652
Dmitry-Mea092bc12014-12-23 17:57:05 +03002653void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002654{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002655 if ( !_elementJustOpened ) {
2656 return;
2657 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002658 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002659 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002660}
2661
2662
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002663void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002664{
Lee Thomason624d43f2012-10-12 10:58:48 -07002665 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002666
Dmitry-Mea092bc12014-12-23 17:57:05 +03002667 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002668 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002669 Write( "<![CDATA[" );
2670 Write( text );
2671 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 }
2673 else {
2674 PrintString( text, true );
2675 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002676}
2677
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002678void XMLPrinter::PushText( int64_t value )
2679{
2680 char buf[BUF_SIZE];
2681 XMLUtil::ToStr( value, buf, BUF_SIZE );
2682 PushText( buf, false );
2683}
2684
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002685void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002686{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002687 char buf[BUF_SIZE];
2688 XMLUtil::ToStr( value, buf, BUF_SIZE );
2689 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002690}
2691
2692
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002693void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002694{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 char buf[BUF_SIZE];
2696 XMLUtil::ToStr( value, buf, BUF_SIZE );
2697 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002698}
2699
2700
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002701void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002702{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002703 char buf[BUF_SIZE];
2704 XMLUtil::ToStr( value, buf, BUF_SIZE );
2705 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002706}
2707
2708
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002709void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 char buf[BUF_SIZE];
2712 XMLUtil::ToStr( value, buf, BUF_SIZE );
2713 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002714}
2715
2716
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002717void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002718{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002719 char buf[BUF_SIZE];
2720 XMLUtil::ToStr( value, buf, BUF_SIZE );
2721 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002722}
2723
Lee Thomason5cae8972012-01-24 18:03:07 -08002724
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002725void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002726{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002727 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002728 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002729 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002730 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002731 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002732 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002733
2734 Write( "<!--" );
2735 Write( comment );
2736 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002737}
Lee Thomason751da522012-02-10 08:50:51 -08002738
2739
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002740void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002741{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002742 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002743 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002744 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002745 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002746 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002747 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002748
2749 Write( "<?" );
2750 Write( value );
2751 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002752}
2753
2754
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002755void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002756{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002757 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002758 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002759 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002760 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002761 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002762 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002763
2764 Write( "<!" );
2765 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002766 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002767}
2768
2769
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002770bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002771{
Lee Thomason624d43f2012-10-12 10:58:48 -07002772 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002773 if ( doc.HasBOM() ) {
2774 PushHeader( true, false );
2775 }
2776 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002777}
2778
2779
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002780bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002781{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002782 const XMLElement* parentElem = 0;
2783 if ( element.Parent() ) {
2784 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002785 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002786 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002787 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002788 while ( attribute ) {
2789 PushAttribute( attribute->Name(), attribute->Value() );
2790 attribute = attribute->Next();
2791 }
2792 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002793}
2794
2795
Uli Kustererca412e82014-02-01 13:35:05 +01002796bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002797{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002798 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002799 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002800}
2801
2802
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002803bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002804{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002805 PushText( text.Value(), text.CData() );
2806 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002807}
2808
2809
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002810bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002811{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002812 PushComment( comment.Value() );
2813 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002814}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002815
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002816bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002817{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002818 PushDeclaration( declaration.Value() );
2819 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002820}
2821
2822
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002823bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002824{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002825 PushUnknown( unknown.Value() );
2826 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002827}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002828
Lee Thomason685b8952012-11-12 13:00:06 -08002829} // namespace tinyxml2