blob: 3182c5ae8f40f09a79a721f3e73d232b90df9bb9 [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 Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300681 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000682 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += xmlHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += commentHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p += cdataHeaderLen;
695 text->SetCData( true );
696 }
697 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += dtdHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += elementHeaderLen;
706 }
707 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000711 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Dmitry-Me02384662015-03-03 16:02:13 +0300714 TIXMLASSERT( returnNode );
715 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 *node = returnNode;
717 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718}
719
720
Lee Thomason751da522012-02-10 08:50:51 -0800721bool XMLDocument::Accept( XMLVisitor* visitor ) const
722{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300723 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( visitor->VisitEnter( *this ) ) {
725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
726 if ( !node->Accept( visitor ) ) {
727 break;
728 }
729 }
730 }
731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735// --------- XMLNode ----------- //
736
737XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _document( doc ),
739 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000740 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200742 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700743 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200744 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746}
747
748
749XMLNode::~XMLNode()
750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( _parent ) {
753 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755}
756
Michael Daumling21626882013-10-22 17:03:37 +0200757const char* XMLNode::Value() const
758{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300759 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530760 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530761 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200762 return _value.GetStr();
763}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800765void XMLNode::SetValue( const char* str, bool staticMem )
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800773}
774
775
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800776void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800777{
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300779 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300780 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800783}
784
785
786void XMLNode::Unlink( XMLNode* child )
787{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300788 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300789 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300790 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 if ( child == _firstChild ) {
792 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 if ( child == _lastChild ) {
795 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 }
Lee Thomasond923c672012-01-23 08:44:25 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 if ( child->_prev ) {
799 child->_prev->_next = child->_next;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700800 child->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700802 if ( child->_next ) {
803 child->_next->_prev = child->_prev;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700804 child->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700806 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800807}
808
809
U-Stream\Leeae25a442012-02-17 17:48:16 -0800810void XMLNode::DeleteChild( XMLNode* node )
811{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300812 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300813 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100815 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700816 TIXMLASSERT(node->_prev == 0);
817 TIXMLASSERT(node->_next == 0);
818 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400819 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800820}
821
822
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
824{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300825 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300826 if ( addThis->_document != _document ) {
827 TIXMLASSERT( false );
828 return 0;
829 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800830 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700831
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 if ( _lastChild ) {
833 TIXMLASSERT( _firstChild );
834 TIXMLASSERT( _lastChild->_next == 0 );
835 _lastChild->_next = addThis;
836 addThis->_prev = _lastChild;
837 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
841 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 TIXMLASSERT( _firstChild == 0 );
843 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800844
Lee Thomason624d43f2012-10-12 10:58:48 -0700845 addThis->_prev = 0;
846 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800850}
851
852
Lee Thomason1ff38e02012-02-14 18:18:16 -0800853XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
854{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300855 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300856 if ( addThis->_document != _document ) {
857 TIXMLASSERT( false );
858 return 0;
859 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800860 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700861
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 if ( _firstChild ) {
863 TIXMLASSERT( _lastChild );
864 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800865
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 _firstChild->_prev = addThis;
867 addThis->_next = _firstChild;
868 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800869
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 }
872 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 TIXMLASSERT( _lastChild == 0 );
874 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 addThis->_prev = 0;
877 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881}
882
883
884XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
885{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300886 TIXMLASSERT( addThis );
887 if ( addThis->_document != _document ) {
888 TIXMLASSERT( false );
889 return 0;
890 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700891
Dmitry-Meabb2d042014-12-09 12:59:31 +0300892 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300895 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 return 0;
897 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700900 // The last node or the only node.
901 return InsertEndChild( addThis );
902 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800903 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 addThis->_prev = afterThis;
905 addThis->_next = afterThis->_next;
906 afterThis->_next->_prev = addThis;
907 afterThis->_next = addThis;
908 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800910}
911
912
913
914
Dmitry-Me886ad972015-07-22 11:00:51 +0300915const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800916{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300917 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300918 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300920 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 }
922 }
923 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800924}
925
926
Dmitry-Me886ad972015-07-22 11:00:51 +0300927const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800928{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300929 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300930 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300932 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 }
934 }
935 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800936}
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
943 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
955 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800960}
961
962
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300963char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800964{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 // This is a recursive method, but thinking about it "at the current level"
966 // it is a pretty simple flat list:
967 // <foo/>
968 // <!-- comment -->
969 //
970 // With a special case:
971 // <foo>
972 // </foo>
973 // <!-- comment -->
974 //
975 // Where the closing element (/foo) *must* be the next thing after the opening
976 // element, and the names must match. BUT the tricky bit is that the closing
977 // element will be read by the child.
978 //
979 // 'endTag' is the end tag for this node, it is returned by a call to a child.
980 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800981
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 while( p && *p ) {
983 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800984
Lee Thomason624d43f2012-10-12 10:58:48 -0700985 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300986 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300987 if ( node == 0 ) {
988 break;
989 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800990
kezenatore3531812016-11-29 19:49:07 +1000991 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000992
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000994 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400996 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000998 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 break;
1001 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001002
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301003 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301004 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001005 // Declarations are only allowed at document level
1006 bool wellLocated = ( ToDocument() != 0 );
1007 if ( wellLocated ) {
1008 // Multiple declarations are allowed but all declarations
1009 // must occur before anything else
1010 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1011 if ( !existingNode->ToDeclaration() ) {
1012 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301013 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001014 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301015 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001016 }
1017 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001018 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001019 DeleteNode( node );
1020 break;
1021 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301022 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301023
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001024 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001026 // We read the end tag. Return it to the parent.
1027 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001028 if ( parentEndTag ) {
1029 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001030 }
1031 node->_memPool->SetTracked(); // created and then immediately deleted.
1032 DeleteNode( node );
1033 return p;
1034 }
1035
1036 // Handle an end tag returned to this level.
1037 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001038 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001039 if ( endTag.Empty() ) {
1040 if ( ele->ClosingType() == XMLElement::OPEN ) {
1041 mismatch = true;
1042 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001044 else {
1045 if ( ele->ClosingType() != XMLElement::OPEN ) {
1046 mismatch = true;
1047 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001048 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001049 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001052 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001053 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001054 DeleteNode( node );
1055 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001056 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 }
JayXondbfdd8f2014-12-12 20:07:14 -05001058 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 }
1060 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001061}
1062
Lee Thomason816d3fa2017-06-05 14:35:55 -07001063/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001064{
1065 if ( node == 0 ) {
1066 return;
1067 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001068 TIXMLASSERT(node->_document);
1069 if (!node->ToDocument()) {
1070 node->_document->MarkInUse(node);
1071 }
1072
Dmitry-Mee3225b12014-09-03 11:03:11 +04001073 MemPool* pool = node->_memPool;
1074 node->~XMLNode();
1075 pool->Free( node );
1076}
1077
Lee Thomason3cebdc42015-01-05 17:16:28 -08001078void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001079{
1080 TIXMLASSERT( insertThis );
1081 TIXMLASSERT( insertThis->_document == _document );
1082
Lee Thomason816d3fa2017-06-05 14:35:55 -07001083 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001084 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001085 }
1086 else {
1087 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001088 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001089 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001090}
1091
Dmitry-Meecb9b072016-10-12 16:44:59 +03001092const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1093{
1094 const XMLElement* element = this->ToElement();
1095 if ( element == 0 ) {
1096 return 0;
1097 }
1098 if ( name == 0 ) {
1099 return element;
1100 }
1101 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1102 return element;
1103 }
1104 return 0;
1105}
1106
Lee Thomason5492a1c2012-01-23 15:32:10 -08001107// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001108char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 const char* start = p;
1111 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001112 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001114 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 }
1116 return p;
1117 }
1118 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001119 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1120 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001121 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001123
kezenator4f756162016-11-29 19:46:27 +10001124 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( p && *p ) {
1126 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001127 }
1128 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001129 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 }
1131 }
1132 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001133}
1134
1135
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001136XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 }
1141 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1142 text->SetCData( this->CData() );
1143 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001144}
1145
1146
1147bool XMLText::ShallowEqual( const XMLNode* compare ) const
1148{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001149 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001150 const XMLText* text = compare->ToText();
1151 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001152}
1153
1154
Lee Thomason56bdd022012-02-09 18:16:58 -08001155bool XMLText::Accept( XMLVisitor* visitor ) const
1156{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001157 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001159}
1160
1161
Lee Thomason3f57d272012-01-11 15:30:03 -08001162// --------- XMLComment ---------- //
1163
Lee Thomasone4422302012-01-20 17:59:50 -08001164XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001165{
1166}
1167
1168
Lee Thomasonce0763e2012-01-11 15:43:54 -08001169XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001170{
Lee Thomason3f57d272012-01-11 15:30:03 -08001171}
1172
1173
kezenator4f756162016-11-29 19:46:27 +10001174char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 // Comment parses as text.
1177 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001178 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001180 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 }
1182 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001183}
1184
1185
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001186XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 }
1191 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1192 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001193}
1194
1195
1196bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1197{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001198 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001199 const XMLComment* comment = compare->ToComment();
1200 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001201}
1202
1203
Lee Thomason751da522012-02-10 08:50:51 -08001204bool XMLComment::Accept( XMLVisitor* visitor ) const
1205{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001206 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001208}
Lee Thomason56bdd022012-02-09 18:16:58 -08001209
1210
Lee Thomason50f97b22012-02-11 16:33:40 -08001211// --------- XMLDeclaration ---------- //
1212
1213XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1214{
1215}
1216
1217
1218XMLDeclaration::~XMLDeclaration()
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001221}
1222
1223
kezenator4f756162016-11-29 19:46:27 +10001224char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 // Declaration parses as text.
1227 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001228 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001230 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 }
1232 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001233}
1234
1235
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001236XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 }
1241 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1242 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001243}
1244
1245
1246bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1247{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001248 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001249 const XMLDeclaration* declaration = compare->ToDeclaration();
1250 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001251}
1252
1253
1254
Lee Thomason50f97b22012-02-11 16:33:40 -08001255bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001259}
1260
1261// --------- XMLUnknown ---------- //
1262
1263XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1264{
1265}
1266
1267
1268XMLUnknown::~XMLUnknown()
1269{
1270}
1271
1272
kezenator4f756162016-11-29 19:46:27 +10001273char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 // Unknown parses as text.
1276 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001277
kezenator4f756162016-11-29 19:46:27 +10001278 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001280 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 }
1282 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001283}
1284
1285
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001286XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001289 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 }
1291 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1292 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001293}
1294
1295
1296bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1297{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001298 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001299 const XMLUnknown* unknown = compare->ToUnknown();
1300 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001301}
1302
1303
Lee Thomason50f97b22012-02-11 16:33:40 -08001304bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1305{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001306 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001308}
1309
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001310// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001311
1312const char* XMLAttribute::Name() const
1313{
1314 return _name.GetStr();
1315}
1316
1317const char* XMLAttribute::Value() const
1318{
1319 return _value.GetStr();
1320}
1321
kezenator4f756162016-11-29 19:46:27 +10001322char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 if ( !p || !*p ) {
1327 return 0;
1328 }
Lee Thomason22aead12012-01-23 13:29:35 -08001329
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001331 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001332 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 return 0;
1334 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001335
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001337 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 if ( *p != '\"' && *p != '\'' ) {
1339 return 0;
1340 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001341
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 char endTag[2] = { *p, 0 };
1343 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001344
kezenator4f756162016-11-29 19:46:27 +10001345 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347}
1348
1349
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001350void XMLAttribute::SetName( const char* n )
1351{
Lee Thomason624d43f2012-10-12 10:58:48 -07001352 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001353}
1354
1355
Lee Thomason2fa81722012-11-09 12:37:46 -08001356XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001359 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 }
1361 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001362}
1363
1364
Lee Thomason2fa81722012-11-09 12:37:46 -08001365XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001368 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 }
1370 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001371}
1372
1373
Lee Thomason51c12712016-06-04 20:18:49 -07001374XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1375{
1376 if (XMLUtil::ToInt64(Value(), value)) {
1377 return XML_SUCCESS;
1378 }
1379 return XML_WRONG_ATTRIBUTE_TYPE;
1380}
1381
1382
Lee Thomason2fa81722012-11-09 12:37:46 -08001383XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001386 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 }
1388 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001389}
1390
1391
Lee Thomason2fa81722012-11-09 12:37:46 -08001392XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001395 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 }
1397 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001398}
1399
1400
Lee Thomason2fa81722012-11-09 12:37:46 -08001401XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001404 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 }
1406 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001407}
1408
1409
1410void XMLAttribute::SetAttribute( const char* v )
1411{
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413}
1414
1415
Lee Thomason1ff38e02012-02-14 18:18:16 -08001416void XMLAttribute::SetAttribute( int v )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 char buf[BUF_SIZE];
1419 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001421}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001422
1423
1424void XMLAttribute::SetAttribute( unsigned v )
1425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 char buf[BUF_SIZE];
1427 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001429}
1430
1431
Lee Thomason51c12712016-06-04 20:18:49 -07001432void XMLAttribute::SetAttribute(int64_t v)
1433{
1434 char buf[BUF_SIZE];
1435 XMLUtil::ToStr(v, buf, BUF_SIZE);
1436 _value.SetStr(buf);
1437}
1438
1439
1440
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441void XMLAttribute::SetAttribute( bool v )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 char buf[BUF_SIZE];
1444 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446}
1447
1448void XMLAttribute::SetAttribute( double v )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453}
1454
1455void XMLAttribute::SetAttribute( float v )
1456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 char buf[BUF_SIZE];
1458 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001460}
1461
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001462
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001463// --------- XMLElement ---------- //
1464XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001465 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467{
1468}
1469
1470
1471XMLElement::~XMLElement()
1472{
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 while( _rootAttribute ) {
1474 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001475 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001478}
1479
1480
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001481const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1482{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001483 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1485 return a;
1486 }
1487 }
1488 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001489}
1490
1491
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001492const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001493{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 const XMLAttribute* a = FindAttribute( name );
1495 if ( !a ) {
1496 return 0;
1497 }
1498 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1499 return a->Value();
1500 }
1501 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001502}
1503
Josh Wittnercf3dd092016-10-11 18:57:17 -07001504int XMLElement::IntAttribute(const char* name, int defaultValue) const
1505{
1506 int i = defaultValue;
1507 QueryIntAttribute(name, &i);
1508 return i;
1509}
1510
1511unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1512{
1513 unsigned i = defaultValue;
1514 QueryUnsignedAttribute(name, &i);
1515 return i;
1516}
1517
1518int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1519{
1520 int64_t i = defaultValue;
1521 QueryInt64Attribute(name, &i);
1522 return i;
1523}
1524
1525bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1526{
1527 bool b = defaultValue;
1528 QueryBoolAttribute(name, &b);
1529 return b;
1530}
1531
1532double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1533{
1534 double d = defaultValue;
1535 QueryDoubleAttribute(name, &d);
1536 return d;
1537}
1538
1539float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1540{
1541 float f = defaultValue;
1542 QueryFloatAttribute(name, &f);
1543 return f;
1544}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001545
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001546const char* XMLElement::GetText() const
1547{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001549 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 }
1551 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001552}
1553
1554
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001555void XMLElement::SetText( const char* inText )
1556{
Uli Kusterer869bb592014-01-21 01:36:16 +01001557 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001558 FirstChild()->SetValue( inText );
1559 else {
1560 XMLText* theText = GetDocument()->NewText( inText );
1561 InsertFirstChild( theText );
1562 }
1563}
1564
Lee Thomason5bb2d802014-01-24 10:42:57 -08001565
1566void XMLElement::SetText( int v )
1567{
1568 char buf[BUF_SIZE];
1569 XMLUtil::ToStr( v, buf, BUF_SIZE );
1570 SetText( buf );
1571}
1572
1573
1574void XMLElement::SetText( unsigned v )
1575{
1576 char buf[BUF_SIZE];
1577 XMLUtil::ToStr( v, buf, BUF_SIZE );
1578 SetText( buf );
1579}
1580
1581
Lee Thomason51c12712016-06-04 20:18:49 -07001582void XMLElement::SetText(int64_t v)
1583{
1584 char buf[BUF_SIZE];
1585 XMLUtil::ToStr(v, buf, BUF_SIZE);
1586 SetText(buf);
1587}
1588
1589
1590void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
1598void XMLElement::SetText( float v )
1599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr( v, buf, BUF_SIZE );
1602 SetText( buf );
1603}
1604
1605
1606void XMLElement::SetText( double v )
1607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr( v, buf, BUF_SIZE );
1610 SetText( buf );
1611}
1612
1613
MortenMacFly4ee49f12013-01-14 20:03:14 +01001614XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001617 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001618 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 return XML_SUCCESS;
1620 }
1621 return XML_CAN_NOT_CONVERT_TEXT;
1622 }
1623 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001624}
1625
1626
MortenMacFly4ee49f12013-01-14 20:03:14 +01001627XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001630 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001631 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 return XML_SUCCESS;
1633 }
1634 return XML_CAN_NOT_CONVERT_TEXT;
1635 }
1636 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001637}
1638
1639
Lee Thomason51c12712016-06-04 20:18:49 -07001640XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1641{
1642 if (FirstChild() && FirstChild()->ToText()) {
1643 const char* t = FirstChild()->Value();
1644 if (XMLUtil::ToInt64(t, ival)) {
1645 return XML_SUCCESS;
1646 }
1647 return XML_CAN_NOT_CONVERT_TEXT;
1648 }
1649 return XML_NO_TEXT_NODE;
1650}
1651
1652
MortenMacFly4ee49f12013-01-14 20:03:14 +01001653XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001654{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001656 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001657 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 return XML_SUCCESS;
1659 }
1660 return XML_CAN_NOT_CONVERT_TEXT;
1661 }
1662 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001663}
1664
1665
MortenMacFly4ee49f12013-01-14 20:03:14 +01001666XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001667{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001669 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001670 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 return XML_SUCCESS;
1672 }
1673 return XML_CAN_NOT_CONVERT_TEXT;
1674 }
1675 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001676}
1677
1678
MortenMacFly4ee49f12013-01-14 20:03:14 +01001679XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001680{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001682 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001683 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 return XML_SUCCESS;
1685 }
1686 return XML_CAN_NOT_CONVERT_TEXT;
1687 }
1688 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001689}
1690
Josh Wittnercf3dd092016-10-11 18:57:17 -07001691int XMLElement::IntText(int defaultValue) const
1692{
1693 int i = defaultValue;
1694 QueryIntText(&i);
1695 return i;
1696}
1697
1698unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1699{
1700 unsigned i = defaultValue;
1701 QueryUnsignedText(&i);
1702 return i;
1703}
1704
1705int64_t XMLElement::Int64Text(int64_t defaultValue) const
1706{
1707 int64_t i = defaultValue;
1708 QueryInt64Text(&i);
1709 return i;
1710}
1711
1712bool XMLElement::BoolText(bool defaultValue) const
1713{
1714 bool b = defaultValue;
1715 QueryBoolText(&b);
1716 return b;
1717}
1718
1719double XMLElement::DoubleText(double defaultValue) const
1720{
1721 double d = defaultValue;
1722 QueryDoubleText(&d);
1723 return d;
1724}
1725
1726float XMLElement::FloatText(float defaultValue) const
1727{
1728 float f = defaultValue;
1729 QueryFloatText(&f);
1730 return f;
1731}
Lee Thomason21be8822012-07-15 17:27:22 -07001732
1733
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001734XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1735{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 XMLAttribute* last = 0;
1737 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1742 break;
1743 }
1744 }
1745 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001746 attrib = CreateAttribute();
1747 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001749 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 }
1752 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001753 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 }
1756 attrib->SetName( name );
1757 }
1758 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001759}
1760
1761
U-Stream\Leeae25a442012-02-17 17:48:16 -08001762void XMLElement::DeleteAttribute( const char* name )
1763{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1767 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 }
1770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001773 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 break;
1775 }
1776 prev = a;
1777 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001778}
1779
1780
kezenator4f756162016-11-29 19:46:27 +10001781char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001782{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 const char* start = p;
1784 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001785
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 // Read the attributes.
1787 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001788 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001789 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001790 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 return 0;
1792 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001793
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001795 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001796 XMLAttribute* attrib = CreateAttribute();
1797 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001798 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001799
kezenatorec694152016-11-26 17:21:43 +10001800 int attrLineNum = attrib->_parseLineNum;
1801
kezenator4f756162016-11-29 19:46:27 +10001802 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001804 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001805 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 return 0;
1807 }
1808 // There is a minor bug here: if the attribute in the source xml
1809 // document is duplicated, it will not be detected and the
1810 // attribute will be doubly added. However, tracking the 'prevAttribute'
1811 // avoids re-scanning the attribute list. Preferring performance for
1812 // now, may reconsider in the future.
1813 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001814 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 }
1817 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001818 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
1821 prevAttribute = attrib;
1822 }
1823 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 else if ( *p == '>' ) {
1825 ++p;
1826 break;
1827 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001828 // end of the tag
1829 else if ( *p == '/' && *(p+1) == '>' ) {
1830 _closingType = CLOSED;
1831 return p+2; // done; sealed element.
1832 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 else {
kezenatorec694152016-11-26 17:21:43 +10001834 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 return 0;
1836 }
1837 }
1838 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001839}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001840
Dmitry-Mee3225b12014-09-03 11:03:11 +04001841void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1842{
1843 if ( attribute == 0 ) {
1844 return;
1845 }
1846 MemPool* pool = attribute->_memPool;
1847 attribute->~XMLAttribute();
1848 pool->Free( attribute );
1849}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001850
Dmitry-Mea60caa22016-11-22 18:28:08 +03001851XMLAttribute* XMLElement::CreateAttribute()
1852{
1853 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1854 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001855 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001856 attrib->_memPool = &_document->_attributePool;
1857 attrib->_memPool->SetTracked();
1858 return attrib;
1859}
1860
Lee Thomason67d61312012-01-24 16:01:51 -08001861//
1862// <ele></ele>
1863// <ele>foo<b>bar</b></ele>
1864//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001865char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001866{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001868 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001869
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 // The closing element is the </element> form. It is
1871 // parsed just like a regular element then deleted from
1872 // the DOM.
1873 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 ++p;
1876 }
Lee Thomason67d61312012-01-24 16:01:51 -08001877
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 p = _value.ParseName( p );
1879 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 return 0;
1881 }
Lee Thomason67d61312012-01-24 16:01:51 -08001882
kezenator4f756162016-11-29 19:46:27 +10001883 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001884 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 return p;
1886 }
Lee Thomason67d61312012-01-24 16:01:51 -08001887
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001888 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001890}
1891
1892
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001893
1894XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1895{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 }
1899 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1900 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1901 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1902 }
1903 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001904}
1905
1906
1907bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1908{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001909 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001911 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001912
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 const XMLAttribute* a=FirstAttribute();
1914 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001915
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 while ( a && b ) {
1917 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1918 return false;
1919 }
1920 a = a->Next();
1921 b = b->Next();
1922 }
1923 if ( a || b ) {
1924 // different count
1925 return false;
1926 }
1927 return true;
1928 }
1929 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001930}
1931
1932
Lee Thomason751da522012-02-10 08:50:51 -08001933bool XMLElement::Accept( XMLVisitor* visitor ) const
1934{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001935 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1938 if ( !node->Accept( visitor ) ) {
1939 break;
1940 }
1941 }
1942 }
1943 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001944}
Lee Thomason56bdd022012-02-09 18:16:58 -08001945
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001946
Lee Thomason3f57d272012-01-11 15:30:03 -08001947// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001948
1949// Warning: List must match 'enum XMLError'
1950const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1951 "XML_SUCCESS",
1952 "XML_NO_ATTRIBUTE",
1953 "XML_WRONG_ATTRIBUTE_TYPE",
1954 "XML_ERROR_FILE_NOT_FOUND",
1955 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1956 "XML_ERROR_FILE_READ_ERROR",
1957 "XML_ERROR_ELEMENT_MISMATCH",
1958 "XML_ERROR_PARSING_ELEMENT",
1959 "XML_ERROR_PARSING_ATTRIBUTE",
1960 "XML_ERROR_IDENTIFYING_TAG",
1961 "XML_ERROR_PARSING_TEXT",
1962 "XML_ERROR_PARSING_CDATA",
1963 "XML_ERROR_PARSING_COMMENT",
1964 "XML_ERROR_PARSING_DECLARATION",
1965 "XML_ERROR_PARSING_UNKNOWN",
1966 "XML_ERROR_EMPTY_DOCUMENT",
1967 "XML_ERROR_MISMATCHED_ELEMENT",
1968 "XML_ERROR_PARSING",
1969 "XML_CAN_NOT_CONVERT_TEXT",
1970 "XML_NO_TEXT_NODE"
1971};
1972
1973
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001974XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _writeBOM( false ),
1977 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001978 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001979 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001980 _errorLineNum( 0 ),
1981 _charBuffer( 0 ),
1982 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001983{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001984 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1985 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001986}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001987
1988
Lee Thomason3f57d272012-01-11 15:30:03 -08001989XMLDocument::~XMLDocument()
1990{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001991 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001992}
1993
1994
Lee Thomason816d3fa2017-06-05 14:35:55 -07001995void XMLDocument::MarkInUse(XMLNode* node)
1996{
1997 TIXMLASSERT(node->_parent == 0);
1998
1999 for (int i = 0; i < _unlinked.Size(); ++i) {
2000 if (node == _unlinked[i]) {
2001 _unlinked.SwapRemove(i);
2002 break;
2003 }
2004 }
2005}
2006
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002007void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002008{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002009 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002010 while( _unlinked.Size()) {
2011 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2012 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002013
Dmitry-Meab37df82014-11-28 12:08:36 +03002014#ifdef DEBUG
2015 const bool hadError = Error();
2016#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002017 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002018
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 delete [] _charBuffer;
2020 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002021
2022#if 0
2023 _textPool.Trace( "text" );
2024 _elementPool.Trace( "element" );
2025 _commentPool.Trace( "comment" );
2026 _attributePool.Trace( "attribute" );
2027#endif
2028
2029#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002030 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002031 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2032 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2033 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2034 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2035 }
2036#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002037}
2038
Lee Thomason3f57d272012-01-11 15:30:03 -08002039
Lee Thomason2c85a712012-01-31 08:24:24 -08002040XMLElement* XMLDocument::NewElement( const char* name )
2041{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002042 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 ele->SetName( name );
2044 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002045}
2046
2047
Lee Thomason1ff38e02012-02-14 18:18:16 -08002048XMLComment* XMLDocument::NewComment( const char* str )
2049{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002050 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 comment->SetValue( str );
2052 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002053}
2054
2055
2056XMLText* XMLDocument::NewText( const char* str )
2057{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002058 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 text->SetValue( str );
2060 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002061}
2062
2063
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002064XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2065{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002066 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2068 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002069}
2070
2071
2072XMLUnknown* XMLDocument::NewUnknown( const char* str )
2073{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002074 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 unk->SetValue( str );
2076 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002077}
2078
Dmitry-Me01578db2014-08-19 10:18:48 +04002079static FILE* callfopen( const char* filepath, const char* mode )
2080{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002081 TIXMLASSERT( filepath );
2082 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002083#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2084 FILE* fp = 0;
2085 errno_t err = fopen_s( &fp, filepath, mode );
2086 if ( err ) {
2087 return 0;
2088 }
2089#else
2090 FILE* fp = fopen( filepath, mode );
2091#endif
2092 return fp;
2093}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002094
2095void XMLDocument::DeleteNode( XMLNode* node ) {
2096 TIXMLASSERT( node );
2097 TIXMLASSERT(node->_document == this );
2098 if (node->_parent) {
2099 node->_parent->DeleteChild( node );
2100 }
2101 else {
2102 // Isn't in the tree.
2103 // Use the parent delete.
2104 // Also, we need to mark it tracked: we 'know'
2105 // it was never used.
2106 node->_memPool->SetTracked();
2107 // Call the static XMLNode version:
2108 XMLNode::DeleteNode(node);
2109 }
2110}
2111
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002112
Lee Thomason2fa81722012-11-09 12:37:46 -08002113XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002114{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002115 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002116 FILE* fp = callfopen( filename, "rb" );
2117 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002118 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 }
2121 LoadFile( fp );
2122 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002124}
2125
Dmitry-Me901fed52015-09-25 10:29:51 +03002126// This is likely overengineered template art to have a check that unsigned long value incremented
2127// by one still fits into size_t. If size_t type is larger than unsigned long type
2128// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2129// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2130// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2131// types sizes relate to each other.
2132template
2133<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2134struct LongFitsIntoSizeTMinusOne {
2135 static bool Fits( unsigned long value )
2136 {
2137 return value < (size_t)-1;
2138 }
2139};
2140
2141template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002142struct LongFitsIntoSizeTMinusOne<false> {
2143 static bool Fits( unsigned long )
2144 {
2145 return true;
2146 }
2147};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002148
Lee Thomason2fa81722012-11-09 12:37:46 -08002149XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002150{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002151 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002153 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002154 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002155 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002156 return _errorID;
2157 }
2158
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002160 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002162 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002163 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002164 return _errorID;
2165 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002166 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002167
Dmitry-Me901fed52015-09-25 10:29:51 +03002168 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002169 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002170 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002171 return _errorID;
2172 }
2173
Dmitry-Me72801b82015-05-07 09:41:39 +03002174 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002175 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002178
Dmitry-Me72801b82015-05-07 09:41:39 +03002179 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002180 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 _charBuffer = new char[size+1];
2182 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002184 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002187
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189
Dmitry-Me97476b72015-01-01 16:15:57 +03002190 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002192}
2193
2194
Lee Thomason2fa81722012-11-09 12:37:46 -08002195XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002196{
Dmitry-Me01578db2014-08-19 10:18:48 +04002197 FILE* fp = callfopen( filename, "w" );
2198 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002199 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 }
2202 SaveFile(fp, compact);
2203 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002205}
2206
2207
Lee Thomason2fa81722012-11-09 12:37:46 -08002208XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002209{
Ant Mitchell189198f2015-03-24 16:20:36 +00002210 // Clear any error from the last save, otherwise it will get reported
2211 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002212 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 XMLPrinter stream( fp, compact );
2214 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002216}
2217
Lee Thomason1ff38e02012-02-14 18:18:16 -08002218
Lee Thomason2fa81722012-11-09 12:37:46 -08002219XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002220{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002221 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002222
Lee Thomason82d32002014-02-21 22:47:18 -08002223 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002224 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 }
2227 if ( len == (size_t)(-1) ) {
2228 len = strlen( p );
2229 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002230 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 _charBuffer = new char[ len+1 ];
2232 memcpy( _charBuffer, p, len );
2233 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002234
Dmitry-Me97476b72015-01-01 16:15:57 +03002235 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002236 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002237 // clean up now essentially dangling memory.
2238 // and the parse fail can put objects in the
2239 // pools that are dead and inaccessible.
2240 DeleteChildren();
2241 _elementPool.Clear();
2242 _attributePool.Clear();
2243 _textPool.Clear();
2244 _commentPool.Clear();
2245 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002247}
2248
2249
PKEuS1c5f99e2013-07-06 11:28:39 +02002250void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002251{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002252 if ( streamer ) {
2253 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002255 else {
2256 XMLPrinter stdoutStreamer( stdout );
2257 Accept( &stdoutStreamer );
2258 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002259}
2260
2261
kezenatorec694152016-11-26 17:21:43 +10002262void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002263{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002264 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002266
2267 _errorStr1.Reset();
2268 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002269 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002270
2271 if (str1)
2272 _errorStr1.SetStr(str1);
2273 if (str2)
2274 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002275}
2276
Lee Thomasone90e9012016-12-24 07:34:39 -08002277/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002278{
kezenator5a700712016-11-26 13:54:42 +10002279 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2280 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002281 TIXMLASSERT( errorName && errorName[0] );
2282 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002283}
Lee Thomason5cae8972012-01-24 18:03:07 -08002284
kezenator5a700712016-11-26 13:54:42 +10002285const char* XMLDocument::ErrorName() const
2286{
Lee Thomasone90e9012016-12-24 07:34:39 -08002287 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002288}
2289
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002290void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002291{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002292 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 static const int LEN = 20;
2294 char buf1[LEN] = { 0 };
2295 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002296
Lee Thomason584af572016-09-05 14:14:16 -07002297 if ( !_errorStr1.Empty() ) {
2298 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Lee Thomason584af572016-09-05 14:14:16 -07002300 if ( !_errorStr2.Empty() ) {
2301 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303
Dmitry-Me2ad43202015-04-16 12:18:58 +03002304 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2305 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2306 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002307 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2308 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002310}
2311
Dmitry-Me97476b72015-01-01 16:15:57 +03002312void XMLDocument::Parse()
2313{
2314 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2315 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002316 _parseCurLineNum = 1;
2317 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002318 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002319 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002320 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002321 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002322 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002323 return;
2324 }
kezenator4f756162016-11-29 19:46:27 +10002325 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002326}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002327
PKEuS1bfb9542013-08-04 13:51:17 +02002328XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002329 _elementJustOpened( false ),
2330 _firstElement( true ),
2331 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002332 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002333 _textDepth( -1 ),
2334 _processEntities( true ),
2335 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002338 _entityFlag[i] = false;
2339 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 }
2341 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002342 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002343 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002344 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002346 _restrictedEntityFlag[(unsigned char)'&'] = true;
2347 _restrictedEntityFlag[(unsigned char)'<'] = true;
2348 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002349 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002350}
2351
2352
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002353void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002354{
2355 va_list va;
2356 va_start( va, format );
2357
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 if ( _fp ) {
2359 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 }
2361 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002362 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 // Close out and re-start the va-args
2364 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002365 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002366 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002367 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002368 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002369 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002371 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002372}
2373
2374
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002375void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002376{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 for( int i=0; i<depth; ++i ) {
2378 Print( " " );
2379 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002380}
2381
2382
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002383void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 // Look for runs of bytes between entities to print.
2386 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002387
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002389 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002390 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002391 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 // Remember, char is sometimes signed. (How many times has that bitten me?)
2393 if ( *q > 0 && *q < ENTITY_RANGE ) {
2394 // Check for entities. If one is found, flush
2395 // the stream up until the entity, write the
2396 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002397 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002399 const size_t delta = q - p;
2400 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002401 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002402 Print( "%.*s", toPrint, p );
2403 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002405 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 for( int i=0; i<NUM_ENTITIES; ++i ) {
2407 if ( entities[i].value == *q ) {
2408 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002409 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 break;
2411 }
2412 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002413 if ( !entityPatternPrinted ) {
2414 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2415 TIXMLASSERT( false );
2416 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 ++p;
2418 }
2419 }
2420 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002421 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 }
2423 }
2424 // Flush the remaining string. This will be the entire
2425 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002426 TIXMLASSERT( p <= q );
2427 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 Print( "%s", p );
2429 }
Lee Thomason857b8682012-01-25 17:50:25 -08002430}
2431
U-Stream\Leeae25a442012-02-17 17:48:16 -08002432
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002433void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002435 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002436 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002437 Print( "%s", bom );
2438 }
2439 if ( writeDec ) {
2440 PushDeclaration( "xml version=\"1.0\"" );
2441 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002442}
2443
2444
Uli Kusterer593a33d2014-02-01 12:48:51 +01002445void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002446{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002447 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002448 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002449
Uli Kusterer593a33d2014-02-01 12:48:51 +01002450 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002452 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002453 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002454 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002456
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002458 _elementJustOpened = true;
2459 _firstElement = false;
2460 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002461}
2462
2463
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002464void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002465{
Lee Thomason624d43f2012-10-12 10:58:48 -07002466 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002467 Print( " %s=\"", name );
2468 PrintString( value, false );
2469 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002470}
2471
2472
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002473void XMLPrinter::PushAttribute( const char* name, int v )
2474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 char buf[BUF_SIZE];
2476 XMLUtil::ToStr( v, buf, BUF_SIZE );
2477 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002478}
2479
2480
2481void XMLPrinter::PushAttribute( const char* name, unsigned v )
2482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 char buf[BUF_SIZE];
2484 XMLUtil::ToStr( v, buf, BUF_SIZE );
2485 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002486}
2487
2488
Lee Thomason51c12712016-06-04 20:18:49 -07002489void XMLPrinter::PushAttribute(const char* name, int64_t v)
2490{
2491 char buf[BUF_SIZE];
2492 XMLUtil::ToStr(v, buf, BUF_SIZE);
2493 PushAttribute(name, buf);
2494}
2495
2496
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002497void XMLPrinter::PushAttribute( const char* name, bool v )
2498{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 char buf[BUF_SIZE];
2500 XMLUtil::ToStr( v, buf, BUF_SIZE );
2501 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002502}
2503
2504
2505void XMLPrinter::PushAttribute( const char* name, double v )
2506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 char buf[BUF_SIZE];
2508 XMLUtil::ToStr( v, buf, BUF_SIZE );
2509 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002510}
2511
2512
Uli Kustererca412e82014-02-01 13:35:05 +01002513void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002514{
Lee Thomason624d43f2012-10-12 10:58:48 -07002515 --_depth;
2516 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002517
Lee Thomason624d43f2012-10-12 10:58:48 -07002518 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002519 Print( "/>" );
2520 }
2521 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002522 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002524 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 }
2526 Print( "</%s>", name );
2527 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002528
Lee Thomason624d43f2012-10-12 10:58:48 -07002529 if ( _textDepth == _depth ) {
2530 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 }
Uli Kustererca412e82014-02-01 13:35:05 +01002532 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 Print( "\n" );
2534 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002535 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002536}
2537
2538
Dmitry-Mea092bc12014-12-23 17:57:05 +03002539void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002540{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002541 if ( !_elementJustOpened ) {
2542 return;
2543 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002544 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002545 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002546}
2547
2548
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002549void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002550{
Lee Thomason624d43f2012-10-12 10:58:48 -07002551 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002552
Dmitry-Mea092bc12014-12-23 17:57:05 +03002553 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002554 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002555 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 }
2557 else {
2558 PrintString( text, true );
2559 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002560}
2561
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002562void XMLPrinter::PushText( int64_t value )
2563{
2564 char buf[BUF_SIZE];
2565 XMLUtil::ToStr( value, buf, BUF_SIZE );
2566 PushText( buf, false );
2567}
2568
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002569void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 char buf[BUF_SIZE];
2572 XMLUtil::ToStr( value, buf, BUF_SIZE );
2573 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002574}
2575
2576
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002577void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002578{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 char buf[BUF_SIZE];
2580 XMLUtil::ToStr( value, buf, BUF_SIZE );
2581 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002582}
2583
2584
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002585void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002587 char buf[BUF_SIZE];
2588 XMLUtil::ToStr( value, buf, BUF_SIZE );
2589 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002590}
2591
2592
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002593void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 char buf[BUF_SIZE];
2596 XMLUtil::ToStr( value, buf, BUF_SIZE );
2597 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002598}
2599
2600
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002601void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002603 char buf[BUF_SIZE];
2604 XMLUtil::ToStr( value, buf, BUF_SIZE );
2605 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002606}
2607
Lee Thomason5cae8972012-01-24 18:03:07 -08002608
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002609void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002610{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002611 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002612 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002614 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002615 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002616 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002618}
Lee Thomason751da522012-02-10 08:50:51 -08002619
2620
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002621void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002622{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002623 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002624 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002625 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002626 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002628 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002629 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002630}
2631
2632
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002633void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002634{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002635 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002636 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002637 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002638 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002639 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002640 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002641 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002642}
2643
2644
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002645bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002646{
Lee Thomason624d43f2012-10-12 10:58:48 -07002647 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002648 if ( doc.HasBOM() ) {
2649 PushHeader( true, false );
2650 }
2651 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002652}
2653
2654
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002655bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002656{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002657 const XMLElement* parentElem = 0;
2658 if ( element.Parent() ) {
2659 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002660 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002661 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002662 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 while ( attribute ) {
2664 PushAttribute( attribute->Name(), attribute->Value() );
2665 attribute = attribute->Next();
2666 }
2667 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002668}
2669
2670
Uli Kustererca412e82014-02-01 13:35:05 +01002671bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002672{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002673 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002674 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002675}
2676
2677
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002678bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002679{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002680 PushText( text.Value(), text.CData() );
2681 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002682}
2683
2684
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002685bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002686{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002687 PushComment( comment.Value() );
2688 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002689}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002690
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002691bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002693 PushDeclaration( declaration.Value() );
2694 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002695}
2696
2697
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002698bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002699{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002700 PushUnknown( unknown.Value() );
2701 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002702}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002703
Lee Thomason685b8952012-11-12 13:00:06 -08002704} // namespace tinyxml2
2705