blob: de3d2fb3061d5dcce2936162eadba2bd7981e78f [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 Thomason331596e2014-09-11 14:56:43 -07001980 "XML_ERROR_PARSING_ELEMENT",
1981 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07001982 "XML_ERROR_PARSING_TEXT",
1983 "XML_ERROR_PARSING_CDATA",
1984 "XML_ERROR_PARSING_COMMENT",
1985 "XML_ERROR_PARSING_DECLARATION",
1986 "XML_ERROR_PARSING_UNKNOWN",
1987 "XML_ERROR_EMPTY_DOCUMENT",
1988 "XML_ERROR_MISMATCHED_ELEMENT",
1989 "XML_ERROR_PARSING",
1990 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07001991 "XML_NO_TEXT_NODE",
1992 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07001993};
1994
1995
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001996XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001998 _writeBOM( false ),
1999 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002000 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002001 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002002 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002003 _errorLineNum( 0 ),
2004 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002005 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002006 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002007 _unlinked(),
2008 _elementPool(),
2009 _attributePool(),
2010 _textPool(),
2011 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002012{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002013 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2014 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002015}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002016
2017
Lee Thomason3f57d272012-01-11 15:30:03 -08002018XMLDocument::~XMLDocument()
2019{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002020 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002021}
2022
2023
Lee Thomason816d3fa2017-06-05 14:35:55 -07002024void XMLDocument::MarkInUse(XMLNode* node)
2025{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002026 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002027 TIXMLASSERT(node->_parent == 0);
2028
2029 for (int i = 0; i < _unlinked.Size(); ++i) {
2030 if (node == _unlinked[i]) {
2031 _unlinked.SwapRemove(i);
2032 break;
2033 }
2034 }
2035}
2036
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002037void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002038{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002039 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002040 while( _unlinked.Size()) {
2041 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2042 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002043
Peter Matula50689912018-01-09 12:52:26 +01002044#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002045 const bool hadError = Error();
2046#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002047 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002048
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 delete [] _charBuffer;
2050 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002051 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002052
2053#if 0
2054 _textPool.Trace( "text" );
2055 _elementPool.Trace( "element" );
2056 _commentPool.Trace( "comment" );
2057 _attributePool.Trace( "attribute" );
2058#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002059
Peter Matula50689912018-01-09 12:52:26 +01002060#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002061 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002062 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2063 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2064 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2065 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2066 }
2067#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002068}
2069
Lee Thomason3f57d272012-01-11 15:30:03 -08002070
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002071void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002072{
2073 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002074 if (target == this) {
2075 return; // technically success - a no-op.
2076 }
Lee Thomason7085f002017-06-01 18:09:43 -07002077
2078 target->Clear();
2079 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2080 target->InsertEndChild(node->DeepClone(target));
2081 }
2082}
2083
Lee Thomason2c85a712012-01-31 08:24:24 -08002084XMLElement* XMLDocument::NewElement( const char* name )
2085{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002086 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 ele->SetName( name );
2088 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002089}
2090
2091
Lee Thomason1ff38e02012-02-14 18:18:16 -08002092XMLComment* XMLDocument::NewComment( const char* str )
2093{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002094 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 comment->SetValue( str );
2096 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002097}
2098
2099
2100XMLText* XMLDocument::NewText( const char* str )
2101{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002102 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 text->SetValue( str );
2104 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002105}
2106
2107
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2109{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002110 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2112 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002113}
2114
2115
2116XMLUnknown* XMLDocument::NewUnknown( const char* str )
2117{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002118 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 unk->SetValue( str );
2120 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002121}
2122
Dmitry-Me01578db2014-08-19 10:18:48 +04002123static FILE* callfopen( const char* filepath, const char* mode )
2124{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002125 TIXMLASSERT( filepath );
2126 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002127#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2128 FILE* fp = 0;
2129 errno_t err = fopen_s( &fp, filepath, mode );
2130 if ( err ) {
2131 return 0;
2132 }
2133#else
2134 FILE* fp = fopen( filepath, mode );
2135#endif
2136 return fp;
2137}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002138
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002139void XMLDocument::DeleteNode( XMLNode* node ) {
2140 TIXMLASSERT( node );
2141 TIXMLASSERT(node->_document == this );
2142 if (node->_parent) {
2143 node->_parent->DeleteChild( node );
2144 }
2145 else {
2146 // Isn't in the tree.
2147 // Use the parent delete.
2148 // Also, we need to mark it tracked: we 'know'
2149 // it was never used.
2150 node->_memPool->SetTracked();
2151 // Call the static XMLNode version:
2152 XMLNode::DeleteNode(node);
2153 }
2154}
2155
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002156
Lee Thomason2fa81722012-11-09 12:37:46 -08002157XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002158{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002159 if ( !filename ) {
2160 TIXMLASSERT( false );
2161 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2162 return _errorID;
2163 }
2164
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002165 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002166 FILE* fp = callfopen( filename, "rb" );
2167 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002168 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 }
2171 LoadFile( fp );
2172 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002174}
2175
Dmitry-Me901fed52015-09-25 10:29:51 +03002176// This is likely overengineered template art to have a check that unsigned long value incremented
2177// by one still fits into size_t. If size_t type is larger than unsigned long type
2178// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2179// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2180// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2181// types sizes relate to each other.
2182template
2183<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2184struct LongFitsIntoSizeTMinusOne {
2185 static bool Fits( unsigned long value )
2186 {
2187 return value < (size_t)-1;
2188 }
2189};
2190
2191template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002192struct LongFitsIntoSizeTMinusOne<false> {
2193 static bool Fits( unsigned long )
2194 {
2195 return true;
2196 }
2197};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002198
Lee Thomason2fa81722012-11-09 12:37:46 -08002199XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002200{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002201 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002202
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002203 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002204 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002205 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002206 return _errorID;
2207 }
2208
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002210 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002212 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002213 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002214 return _errorID;
2215 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002216 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002217
Dmitry-Me901fed52015-09-25 10:29:51 +03002218 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002219 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002220 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002221 return _errorID;
2222 }
2223
Dmitry-Me72801b82015-05-07 09:41:39 +03002224 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002225 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002228
Dmitry-Me72801b82015-05-07 09:41:39 +03002229 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002230 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 _charBuffer = new char[size+1];
2232 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002234 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002237
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002239
Dmitry-Me97476b72015-01-01 16:15:57 +03002240 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242}
2243
2244
Lee Thomason2fa81722012-11-09 12:37:46 -08002245XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002247 if ( !filename ) {
2248 TIXMLASSERT( false );
2249 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2250 return _errorID;
2251 }
2252
Dmitry-Me01578db2014-08-19 10:18:48 +04002253 FILE* fp = callfopen( filename, "w" );
2254 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002255 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 }
2258 SaveFile(fp, compact);
2259 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002260 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002261}
2262
2263
Lee Thomason2fa81722012-11-09 12:37:46 -08002264XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002265{
Ant Mitchell189198f2015-03-24 16:20:36 +00002266 // Clear any error from the last save, otherwise it will get reported
2267 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002268 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 XMLPrinter stream( fp, compact );
2270 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002272}
2273
Lee Thomason1ff38e02012-02-14 18:18:16 -08002274
Lee Thomason2fa81722012-11-09 12:37:46 -08002275XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002276{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002277 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002278
Lee Thomason82d32002014-02-21 22:47:18 -08002279 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002280 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 }
2283 if ( len == (size_t)(-1) ) {
2284 len = strlen( p );
2285 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002286 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 _charBuffer = new char[ len+1 ];
2288 memcpy( _charBuffer, p, len );
2289 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002290
Dmitry-Me97476b72015-01-01 16:15:57 +03002291 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002292 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002293 // clean up now essentially dangling memory.
2294 // and the parse fail can put objects in the
2295 // pools that are dead and inaccessible.
2296 DeleteChildren();
2297 _elementPool.Clear();
2298 _attributePool.Clear();
2299 _textPool.Clear();
2300 _commentPool.Clear();
2301 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002303}
2304
2305
PKEuS1c5f99e2013-07-06 11:28:39 +02002306void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002307{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002308 if ( streamer ) {
2309 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002311 else {
2312 XMLPrinter stdoutStreamer( stdout );
2313 Accept( &stdoutStreamer );
2314 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002315}
2316
2317
Lee Thomasonaa188392017-09-19 17:54:31 -07002318void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002319{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002320 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002321 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002322 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002323 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002324
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002325 size_t BUFFER_SIZE = 1000;
2326 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002327
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002328 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002329 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 -07002330
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002331 if (format) {
2332 size_t len = strlen(buffer);
2333 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2334 len = strlen(buffer);
2335
2336 va_list va;
2337 va_start(va, format);
2338 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2339 va_end(va);
2340 }
2341 _errorStr.SetStr(buffer);
2342 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002343}
2344
Lee Thomasonaa188392017-09-19 17:54:31 -07002345
Lee Thomasone90e9012016-12-24 07:34:39 -08002346/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002347{
kezenator5a700712016-11-26 13:54:42 +10002348 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2349 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002350 TIXMLASSERT( errorName && errorName[0] );
2351 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002352}
Lee Thomason5cae8972012-01-24 18:03:07 -08002353
Gumichan010f1fa6d2018-02-01 14:16:24 +01002354const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002355{
Lee Thomasonaa188392017-09-19 17:54:31 -07002356 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002357}
2358
Lee Thomasonf49b9652017-10-11 10:57:49 -07002359
2360void XMLDocument::PrintError() const
2361{
2362 printf("%s\n", ErrorStr());
2363}
2364
kezenator5a700712016-11-26 13:54:42 +10002365const char* XMLDocument::ErrorName() const
2366{
Lee Thomasone90e9012016-12-24 07:34:39 -08002367 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002368}
2369
Dmitry-Me97476b72015-01-01 16:15:57 +03002370void XMLDocument::Parse()
2371{
2372 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2373 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002374 _parseCurLineNum = 1;
2375 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002376 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002377 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002378 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002379 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002380 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002381 return;
2382 }
kezenator4f756162016-11-29 19:46:27 +10002383 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002384}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002385
Lee Thomasonf928c352018-04-05 09:24:20 -07002386void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002387{
2388 _parsingDepth++;
2389 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002390 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002391 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002392}
2393
Lee Thomasonf928c352018-04-05 09:24:20 -07002394void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002395{
2396 TIXMLASSERT(_parsingDepth > 0);
2397 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002398}
2399
PKEuS1bfb9542013-08-04 13:51:17 +02002400XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002402 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002403 _firstElement( true ),
2404 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002405 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002406 _textDepth( -1 ),
2407 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002408 _compactMode( compact ),
2409 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002412 _entityFlag[i] = false;
2413 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 }
2415 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002416 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002417 const unsigned char flagIndex = (unsigned char)entityValue;
2418 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2419 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002420 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002421 _restrictedEntityFlag[(unsigned char)'&'] = true;
2422 _restrictedEntityFlag[(unsigned char)'<'] = true;
2423 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002424 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002425}
2426
2427
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002428void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002429{
2430 va_list va;
2431 va_start( va, format );
2432
Lee Thomason624d43f2012-10-12 10:58:48 -07002433 if ( _fp ) {
2434 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002435 }
2436 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002437 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 // Close out and re-start the va-args
2439 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002440 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002442 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002443 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002444 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002446 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002447}
2448
2449
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002450void XMLPrinter::Write( const char* data, size_t size )
2451{
2452 if ( _fp ) {
2453 fwrite ( data , sizeof(char), size, _fp);
2454 }
2455 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002456 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002457 memcpy( p, data, size );
2458 p[size] = 0;
2459 }
2460}
2461
2462
2463void XMLPrinter::Putc( char ch )
2464{
2465 if ( _fp ) {
2466 fputc ( ch, _fp);
2467 }
2468 else {
2469 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2470 p[0] = ch;
2471 p[1] = 0;
2472 }
2473}
2474
2475
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002476void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002479 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002481}
2482
2483
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002484void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002486 // Look for runs of bytes between entities to print.
2487 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002488
Lee Thomason624d43f2012-10-12 10:58:48 -07002489 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002490 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002491 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002492 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002493 // Remember, char is sometimes signed. (How many times has that bitten me?)
2494 if ( *q > 0 && *q < ENTITY_RANGE ) {
2495 // Check for entities. If one is found, flush
2496 // the stream up until the entity, write the
2497 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002498 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002500 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002501 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002502 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002503 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002505 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002506 for( int i=0; i<NUM_ENTITIES; ++i ) {
2507 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002508 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002509 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002510 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002511 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002512 break;
2513 }
2514 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002515 if ( !entityPatternPrinted ) {
2516 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2517 TIXMLASSERT( false );
2518 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002519 ++p;
2520 }
2521 }
2522 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002523 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 }
Derek Quambe69ae62018-04-18 13:40:46 -05002525 // Flush the remaining string. This will be the entire
2526 // string if an entity wasn't found.
2527 if ( p < q ) {
2528 const size_t delta = q - p;
2529 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2530 Write( p, toPrint );
2531 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002532 }
Derek Quambe69ae62018-04-18 13:40:46 -05002533 else {
2534 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 }
Lee Thomason857b8682012-01-25 17:50:25 -08002536}
2537
U-Stream\Leeae25a442012-02-17 17:48:16 -08002538
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002539void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002540{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002542 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 +03002543 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 }
2545 if ( writeDec ) {
2546 PushDeclaration( "xml version=\"1.0\"" );
2547 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002548}
2549
2550
Uli Kusterer593a33d2014-02-01 12:48:51 +01002551void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002552{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002553 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002554 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002555
Uli Kusterer593a33d2014-02-01 12:48:51 +01002556 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002557 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002558 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002559 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002560 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002562
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002563 Write ( "<" );
2564 Write ( name );
2565
Lee Thomason624d43f2012-10-12 10:58:48 -07002566 _elementJustOpened = true;
2567 _firstElement = false;
2568 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002569}
2570
2571
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002572void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002573{
Lee Thomason624d43f2012-10-12 10:58:48 -07002574 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002575 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002576 Write( name );
2577 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002578 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002579 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002580}
2581
2582
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002583void XMLPrinter::PushAttribute( const char* name, int v )
2584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002585 char buf[BUF_SIZE];
2586 XMLUtil::ToStr( v, buf, BUF_SIZE );
2587 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002588}
2589
2590
2591void XMLPrinter::PushAttribute( const char* name, unsigned v )
2592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 char buf[BUF_SIZE];
2594 XMLUtil::ToStr( v, buf, BUF_SIZE );
2595 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002596}
2597
2598
Lee Thomason51c12712016-06-04 20:18:49 -07002599void XMLPrinter::PushAttribute(const char* name, int64_t v)
2600{
2601 char buf[BUF_SIZE];
2602 XMLUtil::ToStr(v, buf, BUF_SIZE);
2603 PushAttribute(name, buf);
2604}
2605
2606
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002607void XMLPrinter::PushAttribute( const char* name, bool v )
2608{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 char buf[BUF_SIZE];
2610 XMLUtil::ToStr( v, buf, BUF_SIZE );
2611 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002612}
2613
2614
2615void XMLPrinter::PushAttribute( const char* name, double v )
2616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 char buf[BUF_SIZE];
2618 XMLUtil::ToStr( v, buf, BUF_SIZE );
2619 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002620}
2621
2622
Uli Kustererca412e82014-02-01 13:35:05 +01002623void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002624{
Lee Thomason624d43f2012-10-12 10:58:48 -07002625 --_depth;
2626 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002627
Lee Thomason624d43f2012-10-12 10:58:48 -07002628 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002629 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002630 }
2631 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002632 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002633 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002634 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002635 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002636 Write ( "</" );
2637 Write ( name );
2638 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002639 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002640
Lee Thomason624d43f2012-10-12 10:58:48 -07002641 if ( _textDepth == _depth ) {
2642 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002643 }
Uli Kustererca412e82014-02-01 13:35:05 +01002644 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002645 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002646 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002647 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002648}
2649
2650
Dmitry-Mea092bc12014-12-23 17:57:05 +03002651void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002652{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002653 if ( !_elementJustOpened ) {
2654 return;
2655 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002656 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002657 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002658}
2659
2660
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002661void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002662{
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002664
Dmitry-Mea092bc12014-12-23 17:57:05 +03002665 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002667 Write( "<![CDATA[" );
2668 Write( text );
2669 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002670 }
2671 else {
2672 PrintString( text, true );
2673 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002674}
2675
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002676void XMLPrinter::PushText( int64_t value )
2677{
2678 char buf[BUF_SIZE];
2679 XMLUtil::ToStr( value, buf, BUF_SIZE );
2680 PushText( buf, false );
2681}
2682
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002683void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002684{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002685 char buf[BUF_SIZE];
2686 XMLUtil::ToStr( value, buf, BUF_SIZE );
2687 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002688}
2689
2690
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002691void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002693 char buf[BUF_SIZE];
2694 XMLUtil::ToStr( value, buf, BUF_SIZE );
2695 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002696}
2697
2698
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002699void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002700{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002701 char buf[BUF_SIZE];
2702 XMLUtil::ToStr( value, buf, BUF_SIZE );
2703 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002704}
2705
2706
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002707void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002708{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002709 char buf[BUF_SIZE];
2710 XMLUtil::ToStr( value, buf, BUF_SIZE );
2711 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002712}
2713
2714
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002715void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002716{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002717 char buf[BUF_SIZE];
2718 XMLUtil::ToStr( value, buf, BUF_SIZE );
2719 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002720}
2721
Lee Thomason5cae8972012-01-24 18:03:07 -08002722
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002723void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002724{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002725 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002726 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002727 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002728 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002729 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002730 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002731
2732 Write( "<!--" );
2733 Write( comment );
2734 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002735}
Lee Thomason751da522012-02-10 08:50:51 -08002736
2737
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002738void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002739{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002740 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002741 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002742 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002743 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002744 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002745 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002746
2747 Write( "<?" );
2748 Write( value );
2749 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002750}
2751
2752
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002753void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002754{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002755 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002756 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002757 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002758 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002759 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002760 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002761
2762 Write( "<!" );
2763 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002764 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002765}
2766
2767
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002768bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002769{
Lee Thomason624d43f2012-10-12 10:58:48 -07002770 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002771 if ( doc.HasBOM() ) {
2772 PushHeader( true, false );
2773 }
2774 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002775}
2776
2777
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002778bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002779{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002780 const XMLElement* parentElem = 0;
2781 if ( element.Parent() ) {
2782 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002783 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002784 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002785 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002786 while ( attribute ) {
2787 PushAttribute( attribute->Name(), attribute->Value() );
2788 attribute = attribute->Next();
2789 }
2790 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002791}
2792
2793
Uli Kustererca412e82014-02-01 13:35:05 +01002794bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002795{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002796 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002797 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002798}
2799
2800
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002801bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002802{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002803 PushText( text.Value(), text.CData() );
2804 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002805}
2806
2807
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002808bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002809{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002810 PushComment( comment.Value() );
2811 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002812}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002813
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002814bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002815{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002816 PushDeclaration( declaration.Value() );
2817 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002818}
2819
2820
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002821bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002822{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002823 PushUnknown( unknown.Value() );
2824 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002825}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002826
Lee Thomason685b8952012-11-12 13:00:06 -08002827} // namespace tinyxml2