blob: fd27f7888d279e8f66d4fda506945f38a909bad8 [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
Lee Thomasondb13a822018-07-28 14:56:20 -07001035 //
1036 // Multiple declarations are allowed but all declarations
1037 // must occur before anything else.
1038 //
1039 // Optimized due to a security test case. If the first node is
1040 // a declaration, and the last node is a declaration, then only
1041 // declarations have so far been addded.
1042 bool wellLocated = false;
1043
1044 if (ToDocument()) {
1045 if (FirstChild()) {
1046 wellLocated =
1047 FirstChild() &&
1048 FirstChild()->ToDeclaration() &&
1049 LastChild() &&
1050 LastChild()->ToDeclaration();
1051 }
1052 else {
1053 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301054 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001055 }
1056 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001057 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001058 DeleteNode( node );
1059 break;
1060 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301061 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301062
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001063 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001065 // We read the end tag. Return it to the parent.
1066 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001067 if ( parentEndTag ) {
1068 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001069 }
1070 node->_memPool->SetTracked(); // created and then immediately deleted.
1071 DeleteNode( node );
1072 return p;
1073 }
1074
1075 // Handle an end tag returned to this level.
1076 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001077 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001078 if ( endTag.Empty() ) {
1079 if ( ele->ClosingType() == XMLElement::OPEN ) {
1080 mismatch = true;
1081 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001083 else {
1084 if ( ele->ClosingType() != XMLElement::OPEN ) {
1085 mismatch = true;
1086 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001087 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001088 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 }
1090 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001091 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001092 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001093 DeleteNode( node );
1094 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001095 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 }
JayXondbfdd8f2014-12-12 20:07:14 -05001097 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 }
1099 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001100}
1101
Lee Thomason816d3fa2017-06-05 14:35:55 -07001102/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001103{
1104 if ( node == 0 ) {
1105 return;
1106 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001107 TIXMLASSERT(node->_document);
1108 if (!node->ToDocument()) {
1109 node->_document->MarkInUse(node);
1110 }
1111
Dmitry-Mee3225b12014-09-03 11:03:11 +04001112 MemPool* pool = node->_memPool;
1113 node->~XMLNode();
1114 pool->Free( node );
1115}
1116
Lee Thomason3cebdc42015-01-05 17:16:28 -08001117void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001118{
1119 TIXMLASSERT( insertThis );
1120 TIXMLASSERT( insertThis->_document == _document );
1121
Lee Thomason816d3fa2017-06-05 14:35:55 -07001122 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001123 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001124 }
1125 else {
1126 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001127 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001128 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001129}
1130
Dmitry-Meecb9b072016-10-12 16:44:59 +03001131const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1132{
1133 const XMLElement* element = this->ToElement();
1134 if ( element == 0 ) {
1135 return 0;
1136 }
1137 if ( name == 0 ) {
1138 return element;
1139 }
1140 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1141 return element;
1142 }
1143 return 0;
1144}
1145
Lee Thomason5492a1c2012-01-23 15:32:10 -08001146// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001147char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001150 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001152 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 }
1154 return p;
1155 }
1156 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1158 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001159 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001161
kezenator4f756162016-11-29 19:46:27 +10001162 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 if ( p && *p ) {
1164 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001165 }
1166 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001167 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 }
1169 }
1170 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001171}
1172
1173
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001174XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
1179 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1180 text->SetCData( this->CData() );
1181 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001182}
1183
1184
1185bool XMLText::ShallowEqual( const XMLNode* compare ) const
1186{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001187 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001188 const XMLText* text = compare->ToText();
1189 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001190}
1191
1192
Lee Thomason56bdd022012-02-09 18:16:58 -08001193bool XMLText::Accept( XMLVisitor* visitor ) const
1194{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001195 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001197}
1198
1199
Lee Thomason3f57d272012-01-11 15:30:03 -08001200// --------- XMLComment ---------- //
1201
Lee Thomasone4422302012-01-20 17:59:50 -08001202XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001203{
1204}
1205
1206
Lee Thomasonce0763e2012-01-11 15:43:54 -08001207XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001208{
Lee Thomason3f57d272012-01-11 15:30:03 -08001209}
1210
1211
kezenator4f756162016-11-29 19:46:27 +10001212char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001215 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001217 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 }
1219 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001220}
1221
1222
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001223XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001226 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 }
1228 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1229 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001230}
1231
1232
1233bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1234{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001235 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001236 const XMLComment* comment = compare->ToComment();
1237 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001238}
1239
1240
Lee Thomason751da522012-02-10 08:50:51 -08001241bool XMLComment::Accept( XMLVisitor* visitor ) const
1242{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001243 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001245}
Lee Thomason56bdd022012-02-09 18:16:58 -08001246
1247
Lee Thomason50f97b22012-02-11 16:33:40 -08001248// --------- XMLDeclaration ---------- //
1249
1250XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1251{
1252}
1253
1254
1255XMLDeclaration::~XMLDeclaration()
1256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001258}
1259
1260
kezenator4f756162016-11-29 19:46:27 +10001261char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001262{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001264 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001266 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 }
1268 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001269}
1270
1271
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001272XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 }
1277 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1278 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001279}
1280
1281
1282bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1283{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001284 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001285 const XMLDeclaration* declaration = compare->ToDeclaration();
1286 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001287}
1288
1289
1290
Lee Thomason50f97b22012-02-11 16:33:40 -08001291bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1292{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001293 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001295}
1296
1297// --------- XMLUnknown ---------- //
1298
1299XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1300{
1301}
1302
1303
1304XMLUnknown::~XMLUnknown()
1305{
1306}
1307
1308
kezenator4f756162016-11-29 19:46:27 +10001309char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001310{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001312 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001314 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 }
1316 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001317}
1318
1319
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001320XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001323 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 }
1325 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1326 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001327}
1328
1329
1330bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1331{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001332 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001333 const XMLUnknown* unknown = compare->ToUnknown();
1334 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001335}
1336
1337
Lee Thomason50f97b22012-02-11 16:33:40 -08001338bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1339{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001340 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001342}
1343
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001344// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001345
Gumichan010f1fa6d2018-02-01 14:16:24 +01001346const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001347{
1348 return _name.GetStr();
1349}
1350
Gumichan010f1fa6d2018-02-01 14:16:24 +01001351const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001352{
1353 return _value.GetStr();
1354}
1355
kezenator4f756162016-11-29 19:46:27 +10001356char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 if ( !p || !*p ) {
1361 return 0;
1362 }
Lee Thomason22aead12012-01-23 13:29:35 -08001363
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001365 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001366 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 return 0;
1368 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001369
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001371 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 if ( *p != '\"' && *p != '\'' ) {
1373 return 0;
1374 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001375
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 char endTag[2] = { *p, 0 };
1377 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001378
kezenator4f756162016-11-29 19:46:27 +10001379 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001381}
1382
1383
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001384void XMLAttribute::SetName( const char* n )
1385{
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001387}
1388
1389
Lee Thomason2fa81722012-11-09 12:37:46 -08001390XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001393 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 }
1395 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001396}
1397
1398
Lee Thomason2fa81722012-11-09 12:37:46 -08001399XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001402 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001405}
1406
1407
Lee Thomason51c12712016-06-04 20:18:49 -07001408XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1409{
1410 if (XMLUtil::ToInt64(Value(), value)) {
1411 return XML_SUCCESS;
1412 }
1413 return XML_WRONG_ATTRIBUTE_TYPE;
1414}
1415
1416
Lee Thomason2fa81722012-11-09 12:37:46 -08001417XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001420 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
1422 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001423}
1424
1425
Lee Thomason2fa81722012-11-09 12:37:46 -08001426XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001429 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 }
1431 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001432}
1433
1434
Lee Thomason2fa81722012-11-09 12:37:46 -08001435XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001438 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001441}
1442
1443
1444void XMLAttribute::SetAttribute( const char* v )
1445{
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001447}
1448
1449
Lee Thomason1ff38e02012-02-14 18:18:16 -08001450void XMLAttribute::SetAttribute( int v )
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 char buf[BUF_SIZE];
1453 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001455}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001456
1457
1458void XMLAttribute::SetAttribute( unsigned v )
1459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 char buf[BUF_SIZE];
1461 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001463}
1464
1465
Lee Thomason51c12712016-06-04 20:18:49 -07001466void XMLAttribute::SetAttribute(int64_t v)
1467{
1468 char buf[BUF_SIZE];
1469 XMLUtil::ToStr(v, buf, BUF_SIZE);
1470 _value.SetStr(buf);
1471}
1472
1473
1474
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001475void XMLAttribute::SetAttribute( bool v )
1476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 char buf[BUF_SIZE];
1478 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001480}
1481
1482void XMLAttribute::SetAttribute( double v )
1483{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 char buf[BUF_SIZE];
1485 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487}
1488
1489void XMLAttribute::SetAttribute( float v )
1490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 char buf[BUF_SIZE];
1492 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001496
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001497// --------- XMLElement ---------- //
1498XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001499 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001501{
1502}
1503
1504
1505XMLElement::~XMLElement()
1506{
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 while( _rootAttribute ) {
1508 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001509 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001512}
1513
1514
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001515const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1516{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001517 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1519 return a;
1520 }
1521 }
1522 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001523}
1524
1525
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001526const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 const XMLAttribute* a = FindAttribute( name );
1529 if ( !a ) {
1530 return 0;
1531 }
1532 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1533 return a->Value();
1534 }
1535 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001536}
1537
Gumichan010f1fa6d2018-02-01 14:16:24 +01001538int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001539{
1540 int i = defaultValue;
1541 QueryIntAttribute(name, &i);
1542 return i;
1543}
1544
Gumichan010f1fa6d2018-02-01 14:16:24 +01001545unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001546{
1547 unsigned i = defaultValue;
1548 QueryUnsignedAttribute(name, &i);
1549 return i;
1550}
1551
Gumichan010f1fa6d2018-02-01 14:16:24 +01001552int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001553{
1554 int64_t i = defaultValue;
1555 QueryInt64Attribute(name, &i);
1556 return i;
1557}
1558
Gumichan010f1fa6d2018-02-01 14:16:24 +01001559bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001560{
1561 bool b = defaultValue;
1562 QueryBoolAttribute(name, &b);
1563 return b;
1564}
1565
Gumichan010f1fa6d2018-02-01 14:16:24 +01001566double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001567{
1568 double d = defaultValue;
1569 QueryDoubleAttribute(name, &d);
1570 return d;
1571}
1572
Gumichan010f1fa6d2018-02-01 14:16:24 +01001573float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001574{
1575 float f = defaultValue;
1576 QueryFloatAttribute(name, &f);
1577 return f;
1578}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001579
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001580const char* XMLElement::GetText() const
1581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001583 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 }
1585 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001586}
1587
1588
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001589void XMLElement::SetText( const char* inText )
1590{
Uli Kusterer869bb592014-01-21 01:36:16 +01001591 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001592 FirstChild()->SetValue( inText );
1593 else {
1594 XMLText* theText = GetDocument()->NewText( inText );
1595 InsertFirstChild( theText );
1596 }
1597}
1598
Lee Thomason5bb2d802014-01-24 10:42:57 -08001599
Gumichan010f1fa6d2018-02-01 14:16:24 +01001600void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001601{
1602 char buf[BUF_SIZE];
1603 XMLUtil::ToStr( v, buf, BUF_SIZE );
1604 SetText( buf );
1605}
1606
1607
Gumichan010f1fa6d2018-02-01 14:16:24 +01001608void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001609{
1610 char buf[BUF_SIZE];
1611 XMLUtil::ToStr( v, buf, BUF_SIZE );
1612 SetText( buf );
1613}
1614
1615
Lee Thomason51c12712016-06-04 20:18:49 -07001616void XMLElement::SetText(int64_t v)
1617{
1618 char buf[BUF_SIZE];
1619 XMLUtil::ToStr(v, buf, BUF_SIZE);
1620 SetText(buf);
1621}
1622
1623
1624void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001625{
1626 char buf[BUF_SIZE];
1627 XMLUtil::ToStr( v, buf, BUF_SIZE );
1628 SetText( buf );
1629}
1630
1631
Gumichan010f1fa6d2018-02-01 14:16:24 +01001632void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001633{
1634 char buf[BUF_SIZE];
1635 XMLUtil::ToStr( v, buf, BUF_SIZE );
1636 SetText( buf );
1637}
1638
1639
Gumichan010f1fa6d2018-02-01 14:16:24 +01001640void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001641{
1642 char buf[BUF_SIZE];
1643 XMLUtil::ToStr( v, buf, BUF_SIZE );
1644 SetText( buf );
1645}
1646
1647
MortenMacFly4ee49f12013-01-14 20:03:14 +01001648XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001651 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001652 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 return XML_SUCCESS;
1654 }
1655 return XML_CAN_NOT_CONVERT_TEXT;
1656 }
1657 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001658}
1659
1660
MortenMacFly4ee49f12013-01-14 20:03:14 +01001661XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001662{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001664 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001665 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 return XML_SUCCESS;
1667 }
1668 return XML_CAN_NOT_CONVERT_TEXT;
1669 }
1670 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001671}
1672
1673
Lee Thomason51c12712016-06-04 20:18:49 -07001674XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1675{
1676 if (FirstChild() && FirstChild()->ToText()) {
1677 const char* t = FirstChild()->Value();
1678 if (XMLUtil::ToInt64(t, ival)) {
1679 return XML_SUCCESS;
1680 }
1681 return XML_CAN_NOT_CONVERT_TEXT;
1682 }
1683 return XML_NO_TEXT_NODE;
1684}
1685
1686
MortenMacFly4ee49f12013-01-14 20:03:14 +01001687XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001688{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001690 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001691 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 return XML_SUCCESS;
1693 }
1694 return XML_CAN_NOT_CONVERT_TEXT;
1695 }
1696 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001697}
1698
1699
MortenMacFly4ee49f12013-01-14 20:03:14 +01001700XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001701{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001702 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001703 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001704 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 return XML_SUCCESS;
1706 }
1707 return XML_CAN_NOT_CONVERT_TEXT;
1708 }
1709 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001710}
1711
1712
MortenMacFly4ee49f12013-01-14 20:03:14 +01001713XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001714{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001715 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001716 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001717 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 return XML_SUCCESS;
1719 }
1720 return XML_CAN_NOT_CONVERT_TEXT;
1721 }
1722 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001723}
1724
Josh Wittnercf3dd092016-10-11 18:57:17 -07001725int XMLElement::IntText(int defaultValue) const
1726{
1727 int i = defaultValue;
1728 QueryIntText(&i);
1729 return i;
1730}
1731
1732unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1733{
1734 unsigned i = defaultValue;
1735 QueryUnsignedText(&i);
1736 return i;
1737}
1738
1739int64_t XMLElement::Int64Text(int64_t defaultValue) const
1740{
1741 int64_t i = defaultValue;
1742 QueryInt64Text(&i);
1743 return i;
1744}
1745
1746bool XMLElement::BoolText(bool defaultValue) const
1747{
1748 bool b = defaultValue;
1749 QueryBoolText(&b);
1750 return b;
1751}
1752
1753double XMLElement::DoubleText(double defaultValue) const
1754{
1755 double d = defaultValue;
1756 QueryDoubleText(&d);
1757 return d;
1758}
1759
1760float XMLElement::FloatText(float defaultValue) const
1761{
1762 float f = defaultValue;
1763 QueryFloatText(&f);
1764 return f;
1765}
Lee Thomason21be8822012-07-15 17:27:22 -07001766
1767
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001768XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1769{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 XMLAttribute* last = 0;
1771 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1776 break;
1777 }
1778 }
1779 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001780 attrib = CreateAttribute();
1781 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001783 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
1786 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001787 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 }
1790 attrib->SetName( name );
1791 }
1792 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001793}
1794
1795
U-Stream\Leeae25a442012-02-17 17:48:16 -08001796void XMLElement::DeleteAttribute( const char* name )
1797{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1801 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 }
1804 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001807 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 break;
1809 }
1810 prev = a;
1811 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001812}
1813
1814
kezenator4f756162016-11-29 19:46:27 +10001815char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001816{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001818
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 // Read the attributes.
1820 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001821 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001822 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001823 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 return 0;
1825 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001826
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001828 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001829 XMLAttribute* attrib = CreateAttribute();
1830 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001831 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001832
kezenatorec694152016-11-26 17:21:43 +10001833 int attrLineNum = attrib->_parseLineNum;
1834
kezenator4f756162016-11-29 19:46:27 +10001835 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001837 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001838 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 return 0;
1840 }
1841 // There is a minor bug here: if the attribute in the source xml
1842 // document is duplicated, it will not be detected and the
1843 // attribute will be doubly added. However, tracking the 'prevAttribute'
1844 // avoids re-scanning the attribute list. Preferring performance for
1845 // now, may reconsider in the future.
1846 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001847 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 }
1850 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001851 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
1854 prevAttribute = attrib;
1855 }
1856 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 else if ( *p == '>' ) {
1858 ++p;
1859 break;
1860 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001861 // end of the tag
1862 else if ( *p == '/' && *(p+1) == '>' ) {
1863 _closingType = CLOSED;
1864 return p+2; // done; sealed element.
1865 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001867 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 return 0;
1869 }
1870 }
1871 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001872}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001873
Dmitry-Mee3225b12014-09-03 11:03:11 +04001874void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1875{
1876 if ( attribute == 0 ) {
1877 return;
1878 }
1879 MemPool* pool = attribute->_memPool;
1880 attribute->~XMLAttribute();
1881 pool->Free( attribute );
1882}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001883
Dmitry-Mea60caa22016-11-22 18:28:08 +03001884XMLAttribute* XMLElement::CreateAttribute()
1885{
1886 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1887 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001888 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001889 attrib->_memPool = &_document->_attributePool;
1890 attrib->_memPool->SetTracked();
1891 return attrib;
1892}
1893
Lee Thomason67d61312012-01-24 16:01:51 -08001894//
1895// <ele></ele>
1896// <ele>foo<b>bar</b></ele>
1897//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001898char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001899{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001901 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001902
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 // The closing element is the </element> form. It is
1904 // parsed just like a regular element then deleted from
1905 // the DOM.
1906 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 ++p;
1909 }
Lee Thomason67d61312012-01-24 16:01:51 -08001910
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 p = _value.ParseName( p );
1912 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 return 0;
1914 }
Lee Thomason67d61312012-01-24 16:01:51 -08001915
kezenator4f756162016-11-29 19:46:27 +10001916 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001917 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 return p;
1919 }
Lee Thomason67d61312012-01-24 16:01:51 -08001920
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001921 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001923}
1924
1925
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001926
1927XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 }
1932 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1933 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1934 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1935 }
1936 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001937}
1938
1939
1940bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1941{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001942 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001944 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001945
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 const XMLAttribute* a=FirstAttribute();
1947 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001948
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 while ( a && b ) {
1950 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1951 return false;
1952 }
1953 a = a->Next();
1954 b = b->Next();
1955 }
1956 if ( a || b ) {
1957 // different count
1958 return false;
1959 }
1960 return true;
1961 }
1962 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001963}
1964
1965
Lee Thomason751da522012-02-10 08:50:51 -08001966bool XMLElement::Accept( XMLVisitor* visitor ) const
1967{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001968 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1971 if ( !node->Accept( visitor ) ) {
1972 break;
1973 }
1974 }
1975 }
1976 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001977}
Lee Thomason56bdd022012-02-09 18:16:58 -08001978
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001979
Lee Thomason3f57d272012-01-11 15:30:03 -08001980// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001981
1982// Warning: List must match 'enum XMLError'
1983const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1984 "XML_SUCCESS",
1985 "XML_NO_ATTRIBUTE",
1986 "XML_WRONG_ATTRIBUTE_TYPE",
1987 "XML_ERROR_FILE_NOT_FOUND",
1988 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1989 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07001990 "XML_ERROR_PARSING_ELEMENT",
1991 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07001992 "XML_ERROR_PARSING_TEXT",
1993 "XML_ERROR_PARSING_CDATA",
1994 "XML_ERROR_PARSING_COMMENT",
1995 "XML_ERROR_PARSING_DECLARATION",
1996 "XML_ERROR_PARSING_UNKNOWN",
1997 "XML_ERROR_EMPTY_DOCUMENT",
1998 "XML_ERROR_MISMATCHED_ELEMENT",
1999 "XML_ERROR_PARSING",
2000 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002001 "XML_NO_TEXT_NODE",
2002 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002003};
2004
2005
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002006XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 _writeBOM( false ),
2009 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002010 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002011 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002012 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002013 _errorLineNum( 0 ),
2014 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002015 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002016 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002017 _unlinked(),
2018 _elementPool(),
2019 _attributePool(),
2020 _textPool(),
2021 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002022{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002023 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2024 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002025}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002026
2027
Lee Thomason3f57d272012-01-11 15:30:03 -08002028XMLDocument::~XMLDocument()
2029{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002030 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002031}
2032
2033
Lee Thomason816d3fa2017-06-05 14:35:55 -07002034void XMLDocument::MarkInUse(XMLNode* node)
2035{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002036 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002037 TIXMLASSERT(node->_parent == 0);
2038
2039 for (int i = 0; i < _unlinked.Size(); ++i) {
2040 if (node == _unlinked[i]) {
2041 _unlinked.SwapRemove(i);
2042 break;
2043 }
2044 }
2045}
2046
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002047void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002048{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002049 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002050 while( _unlinked.Size()) {
2051 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2052 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002053
Peter Matula50689912018-01-09 12:52:26 +01002054#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002055 const bool hadError = Error();
2056#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002057 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002058
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 delete [] _charBuffer;
2060 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002061 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002062
2063#if 0
2064 _textPool.Trace( "text" );
2065 _elementPool.Trace( "element" );
2066 _commentPool.Trace( "comment" );
2067 _attributePool.Trace( "attribute" );
2068#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002069
Peter Matula50689912018-01-09 12:52:26 +01002070#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002071 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002072 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2073 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2074 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2075 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2076 }
2077#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002078}
2079
Lee Thomason3f57d272012-01-11 15:30:03 -08002080
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002081void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002082{
2083 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002084 if (target == this) {
2085 return; // technically success - a no-op.
2086 }
Lee Thomason7085f002017-06-01 18:09:43 -07002087
2088 target->Clear();
2089 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2090 target->InsertEndChild(node->DeepClone(target));
2091 }
2092}
2093
Lee Thomason2c85a712012-01-31 08:24:24 -08002094XMLElement* XMLDocument::NewElement( const char* name )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 ele->SetName( name );
2098 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002099}
2100
2101
Lee Thomason1ff38e02012-02-14 18:18:16 -08002102XMLComment* XMLDocument::NewComment( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 comment->SetValue( str );
2106 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002107}
2108
2109
2110XMLText* XMLDocument::NewText( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 text->SetValue( str );
2114 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002115}
2116
2117
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002118XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2119{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002120 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2122 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002123}
2124
2125
2126XMLUnknown* XMLDocument::NewUnknown( const char* str )
2127{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002128 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 unk->SetValue( str );
2130 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002131}
2132
Dmitry-Me01578db2014-08-19 10:18:48 +04002133static FILE* callfopen( const char* filepath, const char* mode )
2134{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002135 TIXMLASSERT( filepath );
2136 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002137#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2138 FILE* fp = 0;
2139 errno_t err = fopen_s( &fp, filepath, mode );
2140 if ( err ) {
2141 return 0;
2142 }
2143#else
2144 FILE* fp = fopen( filepath, mode );
2145#endif
2146 return fp;
2147}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002148
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002149void XMLDocument::DeleteNode( XMLNode* node ) {
2150 TIXMLASSERT( node );
2151 TIXMLASSERT(node->_document == this );
2152 if (node->_parent) {
2153 node->_parent->DeleteChild( node );
2154 }
2155 else {
2156 // Isn't in the tree.
2157 // Use the parent delete.
2158 // Also, we need to mark it tracked: we 'know'
2159 // it was never used.
2160 node->_memPool->SetTracked();
2161 // Call the static XMLNode version:
2162 XMLNode::DeleteNode(node);
2163 }
2164}
2165
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002166
Lee Thomason2fa81722012-11-09 12:37:46 -08002167XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002168{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002169 if ( !filename ) {
2170 TIXMLASSERT( false );
2171 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2172 return _errorID;
2173 }
2174
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002175 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002176 FILE* fp = callfopen( filename, "rb" );
2177 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002178 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 }
2181 LoadFile( fp );
2182 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002184}
2185
Dmitry-Me901fed52015-09-25 10:29:51 +03002186// This is likely overengineered template art to have a check that unsigned long value incremented
2187// by one still fits into size_t. If size_t type is larger than unsigned long type
2188// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2189// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2190// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2191// types sizes relate to each other.
2192template
2193<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2194struct LongFitsIntoSizeTMinusOne {
2195 static bool Fits( unsigned long value )
2196 {
2197 return value < (size_t)-1;
2198 }
2199};
2200
2201template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002202struct LongFitsIntoSizeTMinusOne<false> {
2203 static bool Fits( unsigned long )
2204 {
2205 return true;
2206 }
2207};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002208
Lee Thomason2fa81722012-11-09 12:37:46 -08002209XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002210{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002211 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002212
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002213 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002214 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002215 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002216 return _errorID;
2217 }
2218
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002220 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002222 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002223 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002224 return _errorID;
2225 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002226 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227
Dmitry-Me901fed52015-09-25 10:29:51 +03002228 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002229 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002230 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002231 return _errorID;
2232 }
2233
Dmitry-Me72801b82015-05-07 09:41:39 +03002234 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002235 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002238
Dmitry-Me72801b82015-05-07 09:41:39 +03002239 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002240 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 _charBuffer = new char[size+1];
2242 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002244 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002247
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002249
Dmitry-Me97476b72015-01-01 16:15:57 +03002250 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002252}
2253
2254
Lee Thomason2fa81722012-11-09 12:37:46 -08002255XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002256{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002257 if ( !filename ) {
2258 TIXMLASSERT( false );
2259 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2260 return _errorID;
2261 }
2262
Dmitry-Me01578db2014-08-19 10:18:48 +04002263 FILE* fp = callfopen( filename, "w" );
2264 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002265 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002266 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 }
2268 SaveFile(fp, compact);
2269 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002271}
2272
2273
Lee Thomason2fa81722012-11-09 12:37:46 -08002274XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002275{
Ant Mitchell189198f2015-03-24 16:20:36 +00002276 // Clear any error from the last save, otherwise it will get reported
2277 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002278 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 XMLPrinter stream( fp, compact );
2280 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282}
2283
Lee Thomason1ff38e02012-02-14 18:18:16 -08002284
Lee Thomason2fa81722012-11-09 12:37:46 -08002285XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002286{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002287 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002288
Lee Thomason82d32002014-02-21 22:47:18 -08002289 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002290 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
2293 if ( len == (size_t)(-1) ) {
2294 len = strlen( p );
2295 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002296 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002297 _charBuffer = new char[ len+1 ];
2298 memcpy( _charBuffer, p, len );
2299 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002300
Dmitry-Me97476b72015-01-01 16:15:57 +03002301 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002302 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002303 // clean up now essentially dangling memory.
2304 // and the parse fail can put objects in the
2305 // pools that are dead and inaccessible.
2306 DeleteChildren();
2307 _elementPool.Clear();
2308 _attributePool.Clear();
2309 _textPool.Clear();
2310 _commentPool.Clear();
2311 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002312 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002313}
2314
2315
PKEuS1c5f99e2013-07-06 11:28:39 +02002316void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002317{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002318 if ( streamer ) {
2319 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002321 else {
2322 XMLPrinter stdoutStreamer( stdout );
2323 Accept( &stdoutStreamer );
2324 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002325}
2326
2327
Lee Thomasonaa188392017-09-19 17:54:31 -07002328void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002329{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002330 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002331 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002332 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002333 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002334
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002335 size_t BUFFER_SIZE = 1000;
2336 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002337
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002338 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002339 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 -07002340
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002341 if (format) {
2342 size_t len = strlen(buffer);
2343 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2344 len = strlen(buffer);
2345
2346 va_list va;
2347 va_start(va, format);
2348 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2349 va_end(va);
2350 }
2351 _errorStr.SetStr(buffer);
2352 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002353}
2354
Lee Thomasonaa188392017-09-19 17:54:31 -07002355
Lee Thomasone90e9012016-12-24 07:34:39 -08002356/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002357{
kezenator5a700712016-11-26 13:54:42 +10002358 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2359 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002360 TIXMLASSERT( errorName && errorName[0] );
2361 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002362}
Lee Thomason5cae8972012-01-24 18:03:07 -08002363
Gumichan010f1fa6d2018-02-01 14:16:24 +01002364const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002365{
Lee Thomasonaa188392017-09-19 17:54:31 -07002366 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002367}
2368
Lee Thomasonf49b9652017-10-11 10:57:49 -07002369
2370void XMLDocument::PrintError() const
2371{
2372 printf("%s\n", ErrorStr());
2373}
2374
kezenator5a700712016-11-26 13:54:42 +10002375const char* XMLDocument::ErrorName() const
2376{
Lee Thomasone90e9012016-12-24 07:34:39 -08002377 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002378}
2379
Dmitry-Me97476b72015-01-01 16:15:57 +03002380void XMLDocument::Parse()
2381{
2382 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2383 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002384 _parseCurLineNum = 1;
2385 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002386 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002387 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002388 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002389 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002390 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002391 return;
2392 }
kezenator4f756162016-11-29 19:46:27 +10002393 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002394}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002395
Lee Thomasonf928c352018-04-05 09:24:20 -07002396void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002397{
2398 _parsingDepth++;
2399 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002400 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002401 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002402}
2403
Lee Thomasonf928c352018-04-05 09:24:20 -07002404void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002405{
2406 TIXMLASSERT(_parsingDepth > 0);
2407 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002408}
2409
PKEuS1bfb9542013-08-04 13:51:17 +02002410XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002411 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002412 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002413 _firstElement( true ),
2414 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002415 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002416 _textDepth( -1 ),
2417 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002418 _compactMode( compact ),
2419 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002422 _entityFlag[i] = false;
2423 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 }
2425 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002426 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002427 const unsigned char flagIndex = (unsigned char)entityValue;
2428 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2429 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002431 _restrictedEntityFlag[(unsigned char)'&'] = true;
2432 _restrictedEntityFlag[(unsigned char)'<'] = true;
2433 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002434 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002435}
2436
2437
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002438void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002439{
2440 va_list va;
2441 va_start( va, format );
2442
Lee Thomason624d43f2012-10-12 10:58:48 -07002443 if ( _fp ) {
2444 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 }
2446 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002447 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 // Close out and re-start the va-args
2449 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002450 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002452 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002453 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002454 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002456 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002457}
2458
2459
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002460void XMLPrinter::Write( const char* data, size_t size )
2461{
2462 if ( _fp ) {
2463 fwrite ( data , sizeof(char), size, _fp);
2464 }
2465 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002466 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002467 memcpy( p, data, size );
2468 p[size] = 0;
2469 }
2470}
2471
2472
2473void XMLPrinter::Putc( char ch )
2474{
2475 if ( _fp ) {
2476 fputc ( ch, _fp);
2477 }
2478 else {
2479 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2480 p[0] = ch;
2481 p[1] = 0;
2482 }
2483}
2484
2485
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002486void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002487{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002488 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002489 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002491}
2492
2493
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002494void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002496 // Look for runs of bytes between entities to print.
2497 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002498
Lee Thomason624d43f2012-10-12 10:58:48 -07002499 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002500 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002502 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 // Remember, char is sometimes signed. (How many times has that bitten me?)
2504 if ( *q > 0 && *q < ENTITY_RANGE ) {
2505 // Check for entities. If one is found, flush
2506 // the stream up until the entity, write the
2507 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002508 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002509 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002510 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002511 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002512 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002513 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002515 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 for( int i=0; i<NUM_ENTITIES; ++i ) {
2517 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002518 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002519 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002520 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002521 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 break;
2523 }
2524 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002525 if ( !entityPatternPrinted ) {
2526 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2527 TIXMLASSERT( false );
2528 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002529 ++p;
2530 }
2531 }
2532 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002533 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 }
Derek Quambe69ae62018-04-18 13:40:46 -05002535 // Flush the remaining string. This will be the entire
2536 // string if an entity wasn't found.
2537 if ( p < q ) {
2538 const size_t delta = q - p;
2539 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2540 Write( p, toPrint );
2541 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002542 }
Derek Quambe69ae62018-04-18 13:40:46 -05002543 else {
2544 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002545 }
Lee Thomason857b8682012-01-25 17:50:25 -08002546}
2547
U-Stream\Leeae25a442012-02-17 17:48:16 -08002548
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002549void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002550{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002552 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 +03002553 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002554 }
2555 if ( writeDec ) {
2556 PushDeclaration( "xml version=\"1.0\"" );
2557 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002558}
2559
2560
Uli Kusterer593a33d2014-02-01 12:48:51 +01002561void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002562{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002563 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002564 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002565
Uli Kusterer593a33d2014-02-01 12:48:51 +01002566 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002567 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002568 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002569 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002570 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002572
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002573 Write ( "<" );
2574 Write ( name );
2575
Lee Thomason624d43f2012-10-12 10:58:48 -07002576 _elementJustOpened = true;
2577 _firstElement = false;
2578 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002579}
2580
2581
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002582void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002583{
Lee Thomason624d43f2012-10-12 10:58:48 -07002584 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002585 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002586 Write( name );
2587 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002588 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002589 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002590}
2591
2592
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002593void XMLPrinter::PushAttribute( const char* name, int v )
2594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 char buf[BUF_SIZE];
2596 XMLUtil::ToStr( v, buf, BUF_SIZE );
2597 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002598}
2599
2600
2601void XMLPrinter::PushAttribute( const char* name, unsigned v )
2602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002603 char buf[BUF_SIZE];
2604 XMLUtil::ToStr( v, buf, BUF_SIZE );
2605 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002606}
2607
2608
Lee Thomason51c12712016-06-04 20:18:49 -07002609void XMLPrinter::PushAttribute(const char* name, int64_t v)
2610{
2611 char buf[BUF_SIZE];
2612 XMLUtil::ToStr(v, buf, BUF_SIZE);
2613 PushAttribute(name, buf);
2614}
2615
2616
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002617void XMLPrinter::PushAttribute( const char* name, bool v )
2618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 char buf[BUF_SIZE];
2620 XMLUtil::ToStr( v, buf, BUF_SIZE );
2621 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002622}
2623
2624
2625void XMLPrinter::PushAttribute( const char* name, double v )
2626{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 char buf[BUF_SIZE];
2628 XMLUtil::ToStr( v, buf, BUF_SIZE );
2629 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002630}
2631
2632
Uli Kustererca412e82014-02-01 13:35:05 +01002633void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002634{
Lee Thomason624d43f2012-10-12 10:58:48 -07002635 --_depth;
2636 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002637
Lee Thomason624d43f2012-10-12 10:58:48 -07002638 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002639 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002640 }
2641 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002642 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002643 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002644 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002645 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002646 Write ( "</" );
2647 Write ( name );
2648 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002649 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002650
Lee Thomason624d43f2012-10-12 10:58:48 -07002651 if ( _textDepth == _depth ) {
2652 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002653 }
Uli Kustererca412e82014-02-01 13:35:05 +01002654 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002655 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002656 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002657 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002658}
2659
2660
Dmitry-Mea092bc12014-12-23 17:57:05 +03002661void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002662{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002663 if ( !_elementJustOpened ) {
2664 return;
2665 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002666 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002667 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002668}
2669
2670
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002671void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002672{
Lee Thomason624d43f2012-10-12 10:58:48 -07002673 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002674
Dmitry-Mea092bc12014-12-23 17:57:05 +03002675 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002677 Write( "<![CDATA[" );
2678 Write( text );
2679 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002680 }
2681 else {
2682 PrintString( text, true );
2683 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002684}
2685
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002686void XMLPrinter::PushText( int64_t value )
2687{
2688 char buf[BUF_SIZE];
2689 XMLUtil::ToStr( value, buf, BUF_SIZE );
2690 PushText( buf, false );
2691}
2692
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002693void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002694{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 char buf[BUF_SIZE];
2696 XMLUtil::ToStr( value, buf, BUF_SIZE );
2697 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002698}
2699
2700
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002701void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002702{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002703 char buf[BUF_SIZE];
2704 XMLUtil::ToStr( value, buf, BUF_SIZE );
2705 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002706}
2707
2708
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002709void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 char buf[BUF_SIZE];
2712 XMLUtil::ToStr( value, buf, BUF_SIZE );
2713 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002714}
2715
2716
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002717void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002718{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002719 char buf[BUF_SIZE];
2720 XMLUtil::ToStr( value, buf, BUF_SIZE );
2721 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002722}
2723
2724
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002725void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002726{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002727 char buf[BUF_SIZE];
2728 XMLUtil::ToStr( value, buf, BUF_SIZE );
2729 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002730}
2731
Lee Thomason5cae8972012-01-24 18:03:07 -08002732
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002733void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002734{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002735 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002736 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002737 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002738 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002739 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002740 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002741
2742 Write( "<!--" );
2743 Write( comment );
2744 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002745}
Lee Thomason751da522012-02-10 08:50:51 -08002746
2747
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002748void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002749{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002750 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002751 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002752 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002753 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002754 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002755 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002756
2757 Write( "<?" );
2758 Write( value );
2759 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002760}
2761
2762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002763void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002764{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002765 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002766 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002767 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002768 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002769 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002770 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002771
2772 Write( "<!" );
2773 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002774 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002775}
2776
2777
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002778bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002779{
Lee Thomason624d43f2012-10-12 10:58:48 -07002780 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002781 if ( doc.HasBOM() ) {
2782 PushHeader( true, false );
2783 }
2784 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002785}
2786
2787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002788bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002789{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002790 const XMLElement* parentElem = 0;
2791 if ( element.Parent() ) {
2792 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002793 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002794 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002795 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002796 while ( attribute ) {
2797 PushAttribute( attribute->Name(), attribute->Value() );
2798 attribute = attribute->Next();
2799 }
2800 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002801}
2802
2803
Uli Kustererca412e82014-02-01 13:35:05 +01002804bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002805{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002806 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002807 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002808}
2809
2810
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002811bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002812{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002813 PushText( text.Value(), text.CData() );
2814 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002815}
2816
2817
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002818bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002819{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002820 PushComment( comment.Value() );
2821 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002822}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002823
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002824bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002825{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002826 PushDeclaration( declaration.Value() );
2827 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002828}
2829
2830
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002831bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002832{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002833 PushUnknown( unknown.Value() );
2834 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002835}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002836
Lee Thomason685b8952012-11-12 13:00:06 -08002837} // namespace tinyxml2