blob: e9b275bfc6b700eb9040c3be25caa153c67d62f3 [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 Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800371const char* XMLUtil::ReadBOM( const char* p, bool* bom )
372{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300373 TIXMLASSERT( p );
374 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700375 *bom = false;
376 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
377 // Check for BOM:
378 if ( *(pu+0) == TIXML_UTF_LEAD_0
379 && *(pu+1) == TIXML_UTF_LEAD_1
380 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
381 *bom = true;
382 p += 3;
383 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300384 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800386}
387
388
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 const unsigned long BYTE_MASK = 0xBF;
392 const unsigned long BYTE_MARK = 0x80;
393 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800394
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700395 if (input < 0x80) {
396 *length = 1;
397 }
398 else if ( input < 0x800 ) {
399 *length = 2;
400 }
401 else if ( input < 0x10000 ) {
402 *length = 3;
403 }
404 else if ( input < 0x200000 ) {
405 *length = 4;
406 }
407 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300408 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 return;
410 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800411
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800413
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 // Scary scary fall throughs.
415 switch (*length) {
416 case 4:
417 --output;
418 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
419 input >>= 6;
420 case 3:
421 --output;
422 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
423 input >>= 6;
424 case 2:
425 --output;
426 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
427 input >>= 6;
428 case 1:
429 --output;
430 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100431 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300432 default:
433 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800435}
436
437
438const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 // Presume an entity, and pull it out.
441 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800442
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( *(p+1) == '#' && *(p+2) ) {
444 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300445 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 ptrdiff_t delta = 0;
447 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800448 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 if ( *(p+2) == 'x' ) {
451 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300452 const char* q = p+3;
453 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 return 0;
455 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomason7e67bc82015-01-12 14:05:12 -0800457 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Dmitry-Me9f56e122015-01-12 10:07:54 +0300459 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 return 0;
461 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800462 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800463
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 delta = q-p;
465 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700468 unsigned int digit = 0;
469
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 }
473 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
476 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300477 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 }
479 else {
480 return 0;
481 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100482 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300483 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
484 const unsigned int digitScaled = mult * digit;
485 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
486 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300487 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 mult *= 16;
489 --q;
490 }
491 }
492 else {
493 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300494 const char* q = p+2;
495 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 return 0;
497 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomason7e67bc82015-01-12 14:05:12 -0800499 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Dmitry-Me9f56e122015-01-12 10:07:54 +0300501 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 return 0;
503 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800504 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 delta = q-p;
507 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800508
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 while ( *q != '#' ) {
510 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300511 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100512 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300513 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
514 const unsigned int digitScaled = mult * digit;
515 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
516 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 }
518 else {
519 return 0;
520 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300521 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 mult *= 10;
523 --q;
524 }
525 }
526 // convert the UCS to UTF-8
527 ConvertUTF32ToUTF8( ucs, value, length );
528 return p + delta + 1;
529 }
530 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800531}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800532
533
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700534void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700537}
538
539
540void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700543}
544
545
546void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
547{
Doruk Turakde45d042016-08-28 20:47:08 +0200548 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700549}
550
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800551/*
552 ToStr() of a number is a very tricky topic.
553 https://github.com/leethomason/tinyxml2/issues/106
554*/
Lee Thomason21be8822012-07-15 17:27:22 -0700555void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
556{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800557 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700558}
559
560
561void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
562{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800563 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700564}
565
566
Lee Thomason51c12712016-06-04 20:18:49 -0700567void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
568{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700569 // horrible syntax trick to make the compiler happy about %lld
570 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700571}
572
573
Lee Thomason21be8822012-07-15 17:27:22 -0700574bool XMLUtil::ToInt( const char* str, int* value )
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
577 return true;
578 }
579 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700580}
581
582bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
585 return true;
586 }
587 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700588}
589
590bool XMLUtil::ToBool( const char* str, bool* value )
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 int ival = 0;
593 if ( ToInt( str, &ival )) {
594 *value = (ival==0) ? false : true;
595 return true;
596 }
597 if ( StringEqual( str, "true" ) ) {
598 *value = true;
599 return true;
600 }
601 else if ( StringEqual( str, "false" ) ) {
602 *value = false;
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608
609bool XMLUtil::ToFloat( const char* str, float* value )
610{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
612 return true;
613 }
614 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700615}
616
Lee Thomason51c12712016-06-04 20:18:49 -0700617
Lee Thomason21be8822012-07-15 17:27:22 -0700618bool XMLUtil::ToDouble( const char* str, double* value )
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
Lee Thomason51c12712016-06-04 20:18:49 -0700627bool XMLUtil::ToInt64(const char* str, int64_t* value)
628{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700629 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
630 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
631 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700632 return true;
633 }
634 return false;
635}
636
637
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700638char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800639{
Dmitry-Me02384662015-03-03 16:02:13 +0300640 TIXMLASSERT( node );
641 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400642 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000643 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000644 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300645 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300646 *node = 0;
647 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 return p;
649 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650
Dmitry-Me962083b2015-05-26 11:38:30 +0300651 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const char* xmlHeader = { "<?" };
653 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300655 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 static const int xmlHeaderLen = 2;
659 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300661 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
665 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400666 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
kezenatorec694152016-11-26 17:21:43 +1000670 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 p += xmlHeaderLen;
673 }
674 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300675 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 returnNode = new (_commentPool.Alloc()) XMLComment( this );
kezenatorec694152016-11-26 17:21:43 +1000677 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 p += commentHeaderLen;
680 }
681 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300682 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000685 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += cdataHeaderLen;
688 text->SetCData( true );
689 }
690 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300691 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p += dtdHeaderLen;
696 }
697 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300698 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 returnNode = new (_elementPool.Alloc()) XMLElement( this );
kezenatorec694152016-11-26 17:21:43 +1000700 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 p += elementHeaderLen;
703 }
704 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300705 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 returnNode = new (_textPool.Alloc()) XMLText( this );
707 returnNode->_memPool = &_textPool;
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000710 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800712
Dmitry-Me02384662015-03-03 16:02:13 +0300713 TIXMLASSERT( returnNode );
714 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 *node = returnNode;
716 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717}
718
719
Lee Thomason751da522012-02-10 08:50:51 -0800720bool XMLDocument::Accept( XMLVisitor* visitor ) const
721{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300722 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 if ( visitor->VisitEnter( *this ) ) {
724 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
725 if ( !node->Accept( visitor ) ) {
726 break;
727 }
728 }
729 }
730 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800731}
Lee Thomason56bdd022012-02-09 18:16:58 -0800732
733
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800734// --------- XMLNode ----------- //
735
736XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700737 _document( doc ),
738 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000739 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200741 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700742 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200743 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800744{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745}
746
747
748XMLNode::~XMLNode()
749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 if ( _parent ) {
752 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800754}
755
Michael Daumling21626882013-10-22 17:03:37 +0200756const char* XMLNode::Value() const
757{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300758 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530759 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530760 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200761 return _value.GetStr();
762}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800763
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800764void XMLNode::SetValue( const char* str, bool staticMem )
765{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
769 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800772}
773
774
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800775void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800776{
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300778 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300779 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800782}
783
784
785void XMLNode::Unlink( XMLNode* child )
786{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300787 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300788 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300789 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 if ( child == _firstChild ) {
791 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700792 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 if ( child == _lastChild ) {
794 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 }
Lee Thomasond923c672012-01-23 08:44:25 -0800796
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 if ( child->_prev ) {
798 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 if ( child->_next ) {
801 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700803 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800804}
805
806
U-Stream\Leeae25a442012-02-17 17:48:16 -0800807void XMLNode::DeleteChild( XMLNode* node )
808{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300809 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300810 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100812 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400813 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800814}
815
816
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800817XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
818{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300819 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300820 if ( addThis->_document != _document ) {
821 TIXMLASSERT( false );
822 return 0;
823 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800824 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700825
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 if ( _lastChild ) {
827 TIXMLASSERT( _firstChild );
828 TIXMLASSERT( _lastChild->_next == 0 );
829 _lastChild->_next = addThis;
830 addThis->_prev = _lastChild;
831 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832
Lee Thomason624d43f2012-10-12 10:58:48 -0700833 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
835 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700836 TIXMLASSERT( _firstChild == 0 );
837 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 addThis->_prev = 0;
840 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800844}
845
846
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
848{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300849 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300850 if ( addThis->_document != _document ) {
851 TIXMLASSERT( false );
852 return 0;
853 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800854 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 if ( _firstChild ) {
857 TIXMLASSERT( _lastChild );
858 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 _firstChild->_prev = addThis;
861 addThis->_next = _firstChild;
862 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863
Lee Thomason624d43f2012-10-12 10:58:48 -0700864 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 }
866 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 TIXMLASSERT( _lastChild == 0 );
868 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800869
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 addThis->_prev = 0;
871 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400874 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800875}
876
877
878XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
879{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300880 TIXMLASSERT( addThis );
881 if ( addThis->_document != _document ) {
882 TIXMLASSERT( false );
883 return 0;
884 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700885
Dmitry-Meabb2d042014-12-09 12:59:31 +0300886 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700887
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300889 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 return 0;
891 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 // The last node or the only node.
895 return InsertEndChild( addThis );
896 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800897 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700898 addThis->_prev = afterThis;
899 addThis->_next = afterThis->_next;
900 afterThis->_next->_prev = addThis;
901 afterThis->_next = addThis;
902 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800904}
905
906
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300912 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300914 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 }
916 }
917 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
937 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Dmitry-Me886ad972015-07-22 11:00:51 +0300945const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300947 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300948 const XMLElement* element = node->ToElementWithName( name );
949 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400950 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 }
952 }
953 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954}
955
956
kezenator4f756162016-11-29 19:46:27 +1000957char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800958{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 // This is a recursive method, but thinking about it "at the current level"
960 // it is a pretty simple flat list:
961 // <foo/>
962 // <!-- comment -->
963 //
964 // With a special case:
965 // <foo>
966 // </foo>
967 // <!-- comment -->
968 //
969 // Where the closing element (/foo) *must* be the next thing after the opening
970 // element, and the names must match. BUT the tricky bit is that the closing
971 // element will be read by the child.
972 //
973 // 'endTag' is the end tag for this node, it is returned by a call to a child.
974 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 while( p && *p ) {
977 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800978
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300980 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300981 if ( node == 0 ) {
982 break;
983 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800984
kezenatore3531812016-11-29 19:49:07 +1000985 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000986
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000988 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400990 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000992 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 break;
995 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800996
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530997 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530998 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300999 // Declarations are only allowed at document level
1000 bool wellLocated = ( ToDocument() != 0 );
1001 if ( wellLocated ) {
1002 // Multiple declarations are allowed but all declarations
1003 // must occur before anything else
1004 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1005 if ( !existingNode->ToDeclaration() ) {
1006 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301007 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001008 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301009 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001010 }
1011 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001012 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001013 DeleteNode( node );
1014 break;
1015 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301016 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301017
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001018 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001020 // We read the end tag. Return it to the parent.
1021 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1022 if ( parentEnd ) {
1023 ele->_value.TransferTo( parentEnd );
1024 }
1025 node->_memPool->SetTracked(); // created and then immediately deleted.
1026 DeleteNode( node );
1027 return p;
1028 }
1029
1030 // Handle an end tag returned to this level.
1031 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001032 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001033 if ( endTag.Empty() ) {
1034 if ( ele->ClosingType() == XMLElement::OPEN ) {
1035 mismatch = true;
1036 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001038 else {
1039 if ( ele->ClosingType() != XMLElement::OPEN ) {
1040 mismatch = true;
1041 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001042 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001043 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 }
1045 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001046 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001047 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001048 DeleteNode( node );
1049 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001050 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 }
JayXondbfdd8f2014-12-12 20:07:14 -05001052 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 }
1054 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001055}
1056
Dmitry-Mee3225b12014-09-03 11:03:11 +04001057void XMLNode::DeleteNode( XMLNode* node )
1058{
1059 if ( node == 0 ) {
1060 return;
1061 }
1062 MemPool* pool = node->_memPool;
1063 node->~XMLNode();
1064 pool->Free( node );
1065}
1066
Lee Thomason3cebdc42015-01-05 17:16:28 -08001067void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001068{
1069 TIXMLASSERT( insertThis );
1070 TIXMLASSERT( insertThis->_document == _document );
1071
1072 if ( insertThis->_parent )
1073 insertThis->_parent->Unlink( insertThis );
1074 else
1075 insertThis->_memPool->SetTracked();
1076}
1077
Dmitry-Meecb9b072016-10-12 16:44:59 +03001078const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1079{
1080 const XMLElement* element = this->ToElement();
1081 if ( element == 0 ) {
1082 return 0;
1083 }
1084 if ( name == 0 ) {
1085 return element;
1086 }
1087 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1088 return element;
1089 }
1090 return 0;
1091}
1092
Lee Thomason5492a1c2012-01-23 15:32:10 -08001093// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001094char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 const char* start = p;
1097 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001098 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001100 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 }
1102 return p;
1103 }
1104 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1106 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001107 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001109
kezenator4f756162016-11-29 19:46:27 +10001110 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 if ( p && *p ) {
1112 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001113 }
1114 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001115 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 }
1117 }
1118 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001119}
1120
1121
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001122XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001124 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001125 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 }
1127 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1128 text->SetCData( this->CData() );
1129 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001130}
1131
1132
1133bool XMLText::ShallowEqual( const XMLNode* compare ) const
1134{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001135 const XMLText* text = compare->ToText();
1136 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001137}
1138
1139
Lee Thomason56bdd022012-02-09 18:16:58 -08001140bool XMLText::Accept( XMLVisitor* visitor ) const
1141{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001142 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001144}
1145
1146
Lee Thomason3f57d272012-01-11 15:30:03 -08001147// --------- XMLComment ---------- //
1148
Lee Thomasone4422302012-01-20 17:59:50 -08001149XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001150{
1151}
1152
1153
Lee Thomasonce0763e2012-01-11 15:43:54 -08001154XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001155{
Lee Thomason3f57d272012-01-11 15:30:03 -08001156}
1157
1158
kezenator4f756162016-11-29 19:46:27 +10001159char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 // Comment parses as text.
1162 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001163 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001165 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 }
1167 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001168}
1169
1170
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001171XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001174 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
1176 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1177 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001178}
1179
1180
1181bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1182{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001183 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001184 const XMLComment* comment = compare->ToComment();
1185 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001186}
1187
1188
Lee Thomason751da522012-02-10 08:50:51 -08001189bool XMLComment::Accept( XMLVisitor* visitor ) const
1190{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001191 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001193}
Lee Thomason56bdd022012-02-09 18:16:58 -08001194
1195
Lee Thomason50f97b22012-02-11 16:33:40 -08001196// --------- XMLDeclaration ---------- //
1197
1198XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1199{
1200}
1201
1202
1203XMLDeclaration::~XMLDeclaration()
1204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001206}
1207
1208
kezenator4f756162016-11-29 19:46:27 +10001209char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 // Declaration parses as text.
1212 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001213 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001215 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 }
1217 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001218}
1219
1220
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001221XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 }
1226 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1227 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001228}
1229
1230
1231bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1232{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001233 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001234 const XMLDeclaration* declaration = compare->ToDeclaration();
1235 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001236}
1237
1238
1239
Lee Thomason50f97b22012-02-11 16:33:40 -08001240bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1241{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001242 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001244}
1245
1246// --------- XMLUnknown ---------- //
1247
1248XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1249{
1250}
1251
1252
1253XMLUnknown::~XMLUnknown()
1254{
1255}
1256
1257
kezenator4f756162016-11-29 19:46:27 +10001258char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 // Unknown parses as text.
1261 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262
kezenator4f756162016-11-29 19:46:27 +10001263 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001265 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 }
1267 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001268}
1269
1270
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001271XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 }
1276 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1277 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001278}
1279
1280
1281bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1282{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001283 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001284 const XMLUnknown* unknown = compare->ToUnknown();
1285 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001286}
1287
1288
Lee Thomason50f97b22012-02-11 16:33:40 -08001289bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1290{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001291 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001293}
1294
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001295// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001296
1297const char* XMLAttribute::Name() const
1298{
1299 return _name.GetStr();
1300}
1301
1302const char* XMLAttribute::Value() const
1303{
1304 return _value.GetStr();
1305}
1306
kezenator4f756162016-11-29 19:46:27 +10001307char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001310 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 if ( !p || !*p ) {
1312 return 0;
1313 }
Lee Thomason22aead12012-01-23 13:29:35 -08001314
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001316 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001317 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 return 0;
1319 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001320
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001322 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( *p != '\"' && *p != '\'' ) {
1324 return 0;
1325 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001326
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 char endTag[2] = { *p, 0 };
1328 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001329
kezenator4f756162016-11-29 19:46:27 +10001330 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001332}
1333
1334
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001335void XMLAttribute::SetName( const char* n )
1336{
Lee Thomason624d43f2012-10-12 10:58:48 -07001337 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001338}
1339
1340
Lee Thomason2fa81722012-11-09 12:37:46 -08001341XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001344 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 }
1346 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001347}
1348
1349
Lee Thomason2fa81722012-11-09 12:37:46 -08001350XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001353 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 }
1355 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001356}
1357
1358
Lee Thomason51c12712016-06-04 20:18:49 -07001359XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1360{
1361 if (XMLUtil::ToInt64(Value(), value)) {
1362 return XML_SUCCESS;
1363 }
1364 return XML_WRONG_ATTRIBUTE_TYPE;
1365}
1366
1367
Lee Thomason2fa81722012-11-09 12:37:46 -08001368XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001371 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 }
1373 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001374}
1375
1376
Lee Thomason2fa81722012-11-09 12:37:46 -08001377XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001380 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 }
1382 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001383}
1384
1385
Lee Thomason2fa81722012-11-09 12:37:46 -08001386XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001389 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 }
1391 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001392}
1393
1394
1395void XMLAttribute::SetAttribute( const char* v )
1396{
Lee Thomason624d43f2012-10-12 10:58:48 -07001397 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001398}
1399
1400
Lee Thomason1ff38e02012-02-14 18:18:16 -08001401void XMLAttribute::SetAttribute( int v )
1402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 char buf[BUF_SIZE];
1404 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001405 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001406}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407
1408
1409void XMLAttribute::SetAttribute( unsigned v )
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 char buf[BUF_SIZE];
1412 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001414}
1415
1416
Lee Thomason51c12712016-06-04 20:18:49 -07001417void XMLAttribute::SetAttribute(int64_t v)
1418{
1419 char buf[BUF_SIZE];
1420 XMLUtil::ToStr(v, buf, BUF_SIZE);
1421 _value.SetStr(buf);
1422}
1423
1424
1425
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001426void XMLAttribute::SetAttribute( bool v )
1427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 char buf[BUF_SIZE];
1429 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001431}
1432
1433void XMLAttribute::SetAttribute( double v )
1434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 char buf[BUF_SIZE];
1436 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438}
1439
1440void XMLAttribute::SetAttribute( float v )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001445}
1446
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001447
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001448// --------- XMLElement ---------- //
1449XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _closingType( 0 ),
1451 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001452{
1453}
1454
1455
1456XMLElement::~XMLElement()
1457{
Lee Thomason624d43f2012-10-12 10:58:48 -07001458 while( _rootAttribute ) {
1459 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001460 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001463}
1464
1465
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001466const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1467{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001468 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1470 return a;
1471 }
1472 }
1473 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001474}
1475
1476
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001477const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 const XMLAttribute* a = FindAttribute( name );
1480 if ( !a ) {
1481 return 0;
1482 }
1483 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1484 return a->Value();
1485 }
1486 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001487}
1488
Josh Wittnercf3dd092016-10-11 18:57:17 -07001489int XMLElement::IntAttribute(const char* name, int defaultValue) const
1490{
1491 int i = defaultValue;
1492 QueryIntAttribute(name, &i);
1493 return i;
1494}
1495
1496unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1497{
1498 unsigned i = defaultValue;
1499 QueryUnsignedAttribute(name, &i);
1500 return i;
1501}
1502
1503int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1504{
1505 int64_t i = defaultValue;
1506 QueryInt64Attribute(name, &i);
1507 return i;
1508}
1509
1510bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1511{
1512 bool b = defaultValue;
1513 QueryBoolAttribute(name, &b);
1514 return b;
1515}
1516
1517double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1518{
1519 double d = defaultValue;
1520 QueryDoubleAttribute(name, &d);
1521 return d;
1522}
1523
1524float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1525{
1526 float f = defaultValue;
1527 QueryFloatAttribute(name, &f);
1528 return f;
1529}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001530
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001531const char* XMLElement::GetText() const
1532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001534 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 }
1536 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001537}
1538
1539
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001540void XMLElement::SetText( const char* inText )
1541{
Uli Kusterer869bb592014-01-21 01:36:16 +01001542 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001543 FirstChild()->SetValue( inText );
1544 else {
1545 XMLText* theText = GetDocument()->NewText( inText );
1546 InsertFirstChild( theText );
1547 }
1548}
1549
Lee Thomason5bb2d802014-01-24 10:42:57 -08001550
1551void XMLElement::SetText( int v )
1552{
1553 char buf[BUF_SIZE];
1554 XMLUtil::ToStr( v, buf, BUF_SIZE );
1555 SetText( buf );
1556}
1557
1558
1559void XMLElement::SetText( unsigned v )
1560{
1561 char buf[BUF_SIZE];
1562 XMLUtil::ToStr( v, buf, BUF_SIZE );
1563 SetText( buf );
1564}
1565
1566
Lee Thomason51c12712016-06-04 20:18:49 -07001567void XMLElement::SetText(int64_t v)
1568{
1569 char buf[BUF_SIZE];
1570 XMLUtil::ToStr(v, buf, BUF_SIZE);
1571 SetText(buf);
1572}
1573
1574
1575void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001576{
1577 char buf[BUF_SIZE];
1578 XMLUtil::ToStr( v, buf, BUF_SIZE );
1579 SetText( buf );
1580}
1581
1582
1583void XMLElement::SetText( float v )
1584{
1585 char buf[BUF_SIZE];
1586 XMLUtil::ToStr( v, buf, BUF_SIZE );
1587 SetText( buf );
1588}
1589
1590
1591void XMLElement::SetText( double v )
1592{
1593 char buf[BUF_SIZE];
1594 XMLUtil::ToStr( v, buf, BUF_SIZE );
1595 SetText( buf );
1596}
1597
1598
MortenMacFly4ee49f12013-01-14 20:03:14 +01001599XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001602 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001603 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 return XML_SUCCESS;
1605 }
1606 return XML_CAN_NOT_CONVERT_TEXT;
1607 }
1608 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001609}
1610
1611
MortenMacFly4ee49f12013-01-14 20:03:14 +01001612XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001615 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001616 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 return XML_SUCCESS;
1618 }
1619 return XML_CAN_NOT_CONVERT_TEXT;
1620 }
1621 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001622}
1623
1624
Lee Thomason51c12712016-06-04 20:18:49 -07001625XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1626{
1627 if (FirstChild() && FirstChild()->ToText()) {
1628 const char* t = FirstChild()->Value();
1629 if (XMLUtil::ToInt64(t, ival)) {
1630 return XML_SUCCESS;
1631 }
1632 return XML_CAN_NOT_CONVERT_TEXT;
1633 }
1634 return XML_NO_TEXT_NODE;
1635}
1636
1637
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001641 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001642 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
MortenMacFly4ee49f12013-01-14 20:03:14 +01001664XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001665{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001667 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001668 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001674}
1675
Josh Wittnercf3dd092016-10-11 18:57:17 -07001676int XMLElement::IntText(int defaultValue) const
1677{
1678 int i = defaultValue;
1679 QueryIntText(&i);
1680 return i;
1681}
1682
1683unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1684{
1685 unsigned i = defaultValue;
1686 QueryUnsignedText(&i);
1687 return i;
1688}
1689
1690int64_t XMLElement::Int64Text(int64_t defaultValue) const
1691{
1692 int64_t i = defaultValue;
1693 QueryInt64Text(&i);
1694 return i;
1695}
1696
1697bool XMLElement::BoolText(bool defaultValue) const
1698{
1699 bool b = defaultValue;
1700 QueryBoolText(&b);
1701 return b;
1702}
1703
1704double XMLElement::DoubleText(double defaultValue) const
1705{
1706 double d = defaultValue;
1707 QueryDoubleText(&d);
1708 return d;
1709}
1710
1711float XMLElement::FloatText(float defaultValue) const
1712{
1713 float f = defaultValue;
1714 QueryFloatText(&f);
1715 return f;
1716}
Lee Thomason21be8822012-07-15 17:27:22 -07001717
1718
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001719XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 XMLAttribute* last = 0;
1722 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1727 break;
1728 }
1729 }
1730 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001731 attrib = CreateAttribute();
1732 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001734 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 }
1737 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001738 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 }
1741 attrib->SetName( name );
1742 }
1743 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001744}
1745
1746
U-Stream\Leeae25a442012-02-17 17:48:16 -08001747void XMLElement::DeleteAttribute( const char* name )
1748{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1752 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001758 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 break;
1760 }
1761 prev = a;
1762 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001763}
1764
1765
kezenator4f756162016-11-29 19:46:27 +10001766char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001767{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 const char* start = p;
1769 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001770
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 // Read the attributes.
1772 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001773 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001774 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001775 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 return 0;
1777 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001778
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001780 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001781 XMLAttribute* attrib = CreateAttribute();
1782 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001783 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001784
kezenatorec694152016-11-26 17:21:43 +10001785 int attrLineNum = attrib->_parseLineNum;
1786
kezenator4f756162016-11-29 19:46:27 +10001787 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001789 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001790 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 return 0;
1792 }
1793 // There is a minor bug here: if the attribute in the source xml
1794 // document is duplicated, it will not be detected and the
1795 // attribute will be doubly added. However, tracking the 'prevAttribute'
1796 // avoids re-scanning the attribute list. Preferring performance for
1797 // now, may reconsider in the future.
1798 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001799 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001800 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 }
1802 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001803 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
1806 prevAttribute = attrib;
1807 }
1808 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 else if ( *p == '>' ) {
1810 ++p;
1811 break;
1812 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001813 // end of the tag
1814 else if ( *p == '/' && *(p+1) == '>' ) {
1815 _closingType = CLOSED;
1816 return p+2; // done; sealed element.
1817 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 else {
kezenatorec694152016-11-26 17:21:43 +10001819 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 return 0;
1821 }
1822 }
1823 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001824}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001825
Dmitry-Mee3225b12014-09-03 11:03:11 +04001826void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1827{
1828 if ( attribute == 0 ) {
1829 return;
1830 }
1831 MemPool* pool = attribute->_memPool;
1832 attribute->~XMLAttribute();
1833 pool->Free( attribute );
1834}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001835
Dmitry-Mea60caa22016-11-22 18:28:08 +03001836XMLAttribute* XMLElement::CreateAttribute()
1837{
1838 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1839 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1840 attrib->_memPool = &_document->_attributePool;
1841 attrib->_memPool->SetTracked();
1842 return attrib;
1843}
1844
Lee Thomason67d61312012-01-24 16:01:51 -08001845//
1846// <ele></ele>
1847// <ele>foo<b>bar</b></ele>
1848//
kezenator4f756162016-11-29 19:46:27 +10001849char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001850{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001852 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001853
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 // The closing element is the </element> form. It is
1855 // parsed just like a regular element then deleted from
1856 // the DOM.
1857 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 ++p;
1860 }
Lee Thomason67d61312012-01-24 16:01:51 -08001861
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 p = _value.ParseName( p );
1863 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 return 0;
1865 }
Lee Thomason67d61312012-01-24 16:01:51 -08001866
kezenator4f756162016-11-29 19:46:27 +10001867 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 return p;
1870 }
Lee Thomason67d61312012-01-24 16:01:51 -08001871
kezenator4f756162016-11-29 19:46:27 +10001872 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001874}
1875
1876
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001877
1878XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1879{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 }
1883 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1884 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1885 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1886 }
1887 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001888}
1889
1890
1891bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1892{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001893 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001895 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001896
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 const XMLAttribute* a=FirstAttribute();
1898 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001899
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 while ( a && b ) {
1901 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1902 return false;
1903 }
1904 a = a->Next();
1905 b = b->Next();
1906 }
1907 if ( a || b ) {
1908 // different count
1909 return false;
1910 }
1911 return true;
1912 }
1913 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001914}
1915
1916
Lee Thomason751da522012-02-10 08:50:51 -08001917bool XMLElement::Accept( XMLVisitor* visitor ) const
1918{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001919 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1922 if ( !node->Accept( visitor ) ) {
1923 break;
1924 }
1925 }
1926 }
1927 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001928}
Lee Thomason56bdd022012-02-09 18:16:58 -08001929
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001930
Lee Thomason3f57d272012-01-11 15:30:03 -08001931// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001932
1933// Warning: List must match 'enum XMLError'
1934const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1935 "XML_SUCCESS",
1936 "XML_NO_ATTRIBUTE",
1937 "XML_WRONG_ATTRIBUTE_TYPE",
1938 "XML_ERROR_FILE_NOT_FOUND",
1939 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1940 "XML_ERROR_FILE_READ_ERROR",
1941 "XML_ERROR_ELEMENT_MISMATCH",
1942 "XML_ERROR_PARSING_ELEMENT",
1943 "XML_ERROR_PARSING_ATTRIBUTE",
1944 "XML_ERROR_IDENTIFYING_TAG",
1945 "XML_ERROR_PARSING_TEXT",
1946 "XML_ERROR_PARSING_CDATA",
1947 "XML_ERROR_PARSING_COMMENT",
1948 "XML_ERROR_PARSING_DECLARATION",
1949 "XML_ERROR_PARSING_UNKNOWN",
1950 "XML_ERROR_EMPTY_DOCUMENT",
1951 "XML_ERROR_MISMATCHED_ELEMENT",
1952 "XML_ERROR_PARSING",
1953 "XML_CAN_NOT_CONVERT_TEXT",
1954 "XML_NO_TEXT_NODE"
1955};
1956
1957
Lee Thomason624d43f2012-10-12 10:58:48 -07001958XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 _writeBOM( false ),
1961 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001962 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 _whitespace( whitespace ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001964 _errorLineNum( 0 ),
1965 _charBuffer( 0 ),
1966 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001967{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001968 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1969 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001970}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001971
1972
Lee Thomason3f57d272012-01-11 15:30:03 -08001973XMLDocument::~XMLDocument()
1974{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001975 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001976}
1977
1978
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001979void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001980{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001981 DeleteChildren();
1982
Dmitry-Meab37df82014-11-28 12:08:36 +03001983#ifdef DEBUG
1984 const bool hadError = Error();
1985#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001986 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001987
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 delete [] _charBuffer;
1989 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001990
1991#if 0
1992 _textPool.Trace( "text" );
1993 _elementPool.Trace( "element" );
1994 _commentPool.Trace( "comment" );
1995 _attributePool.Trace( "attribute" );
1996#endif
1997
1998#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001999 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002000 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2001 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2002 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2003 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2004 }
2005#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002006}
2007
Lee Thomason3f57d272012-01-11 15:30:03 -08002008
Lee Thomason2c85a712012-01-31 08:24:24 -08002009XMLElement* XMLDocument::NewElement( const char* name )
2010{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002011 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002012 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
2013 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 ele->SetName( name );
2015 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002016}
2017
2018
Lee Thomason1ff38e02012-02-14 18:18:16 -08002019XMLComment* XMLDocument::NewComment( const char* str )
2020{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002021 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
2023 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 comment->SetValue( str );
2025 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002026}
2027
2028
2029XMLText* XMLDocument::NewText( const char* str )
2030{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002031 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 XMLText* text = new (_textPool.Alloc()) XMLText( this );
2033 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 text->SetValue( str );
2035 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002036}
2037
2038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002039XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2040{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002041 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2043 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2045 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002046}
2047
2048
2049XMLUnknown* XMLDocument::NewUnknown( const char* str )
2050{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002051 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2053 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 unk->SetValue( str );
2055 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002056}
2057
Dmitry-Me01578db2014-08-19 10:18:48 +04002058static FILE* callfopen( const char* filepath, const char* mode )
2059{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002060 TIXMLASSERT( filepath );
2061 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002062#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2063 FILE* fp = 0;
2064 errno_t err = fopen_s( &fp, filepath, mode );
2065 if ( err ) {
2066 return 0;
2067 }
2068#else
2069 FILE* fp = fopen( filepath, mode );
2070#endif
2071 return fp;
2072}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002073
2074void XMLDocument::DeleteNode( XMLNode* node ) {
2075 TIXMLASSERT( node );
2076 TIXMLASSERT(node->_document == this );
2077 if (node->_parent) {
2078 node->_parent->DeleteChild( node );
2079 }
2080 else {
2081 // Isn't in the tree.
2082 // Use the parent delete.
2083 // Also, we need to mark it tracked: we 'know'
2084 // it was never used.
2085 node->_memPool->SetTracked();
2086 // Call the static XMLNode version:
2087 XMLNode::DeleteNode(node);
2088 }
2089}
2090
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002091
Lee Thomason2fa81722012-11-09 12:37:46 -08002092XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002093{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002094 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002095 FILE* fp = callfopen( filename, "rb" );
2096 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002097 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002098 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 }
2100 LoadFile( fp );
2101 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002102 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002103}
2104
Dmitry-Me901fed52015-09-25 10:29:51 +03002105// This is likely overengineered template art to have a check that unsigned long value incremented
2106// by one still fits into size_t. If size_t type is larger than unsigned long type
2107// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2108// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2109// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2110// types sizes relate to each other.
2111template
2112<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2113struct LongFitsIntoSizeTMinusOne {
2114 static bool Fits( unsigned long value )
2115 {
2116 return value < (size_t)-1;
2117 }
2118};
2119
2120template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002121struct LongFitsIntoSizeTMinusOne<false> {
2122 static bool Fits( unsigned long )
2123 {
2124 return true;
2125 }
2126};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002127
Lee Thomason2fa81722012-11-09 12:37:46 -08002128XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002129{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002130 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002131
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002132 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002133 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002134 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002135 return _errorID;
2136 }
2137
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002139 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002141 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002142 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002143 return _errorID;
2144 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002145 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146
Dmitry-Me901fed52015-09-25 10:29:51 +03002147 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002148 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002149 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002150 return _errorID;
2151 }
2152
Dmitry-Me72801b82015-05-07 09:41:39 +03002153 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002154 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002157
Dmitry-Me72801b82015-05-07 09:41:39 +03002158 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002159 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _charBuffer = new char[size+1];
2161 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002163 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002166
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002168
Dmitry-Me97476b72015-01-01 16:15:57 +03002169 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002171}
2172
2173
Lee Thomason2fa81722012-11-09 12:37:46 -08002174XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002175{
Dmitry-Me01578db2014-08-19 10:18:48 +04002176 FILE* fp = callfopen( filename, "w" );
2177 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002178 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 }
2181 SaveFile(fp, compact);
2182 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002184}
2185
2186
Lee Thomason2fa81722012-11-09 12:37:46 -08002187XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002188{
Ant Mitchell189198f2015-03-24 16:20:36 +00002189 // Clear any error from the last save, otherwise it will get reported
2190 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002191 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 XMLPrinter stream( fp, compact );
2193 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002195}
2196
Lee Thomason1ff38e02012-02-14 18:18:16 -08002197
Lee Thomason2fa81722012-11-09 12:37:46 -08002198XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002199{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002200 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002201
Lee Thomason82d32002014-02-21 22:47:18 -08002202 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002203 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 }
2206 if ( len == (size_t)(-1) ) {
2207 len = strlen( p );
2208 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002209 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002210 _charBuffer = new char[ len+1 ];
2211 memcpy( _charBuffer, p, len );
2212 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002213
Dmitry-Me97476b72015-01-01 16:15:57 +03002214 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002215 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002216 // clean up now essentially dangling memory.
2217 // and the parse fail can put objects in the
2218 // pools that are dead and inaccessible.
2219 DeleteChildren();
2220 _elementPool.Clear();
2221 _attributePool.Clear();
2222 _textPool.Clear();
2223 _commentPool.Clear();
2224 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002226}
2227
2228
PKEuS1c5f99e2013-07-06 11:28:39 +02002229void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002230{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002231 if ( streamer ) {
2232 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002234 else {
2235 XMLPrinter stdoutStreamer( stdout );
2236 Accept( &stdoutStreamer );
2237 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002238}
2239
2240
kezenatorec694152016-11-26 17:21:43 +10002241void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002242{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002243 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002245
2246 _errorStr1.Reset();
2247 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002248 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002249
2250 if (str1)
2251 _errorStr1.SetStr(str1);
2252 if (str2)
2253 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002254}
2255
Lee Thomasone90e9012016-12-24 07:34:39 -08002256/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002257{
kezenator5a700712016-11-26 13:54:42 +10002258 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2259 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002260 TIXMLASSERT( errorName && errorName[0] );
2261 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002262}
Lee Thomason5cae8972012-01-24 18:03:07 -08002263
kezenator5a700712016-11-26 13:54:42 +10002264const char* XMLDocument::ErrorName() const
2265{
Lee Thomasone90e9012016-12-24 07:34:39 -08002266 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002267}
2268
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002269void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002270{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002271 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 static const int LEN = 20;
2273 char buf1[LEN] = { 0 };
2274 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002275
Lee Thomason584af572016-09-05 14:14:16 -07002276 if ( !_errorStr1.Empty() ) {
2277 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 }
Lee Thomason584af572016-09-05 14:14:16 -07002279 if ( !_errorStr2.Empty() ) {
2280 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282
Dmitry-Me2ad43202015-04-16 12:18:58 +03002283 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2284 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2285 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002286 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2287 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002289}
2290
Dmitry-Me97476b72015-01-01 16:15:57 +03002291void XMLDocument::Parse()
2292{
2293 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2294 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002295 _parseCurLineNum = 1;
2296 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002297 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002298 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002299 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002300 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002301 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002302 return;
2303 }
kezenator4f756162016-11-29 19:46:27 +10002304 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002305}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306
PKEuS1bfb9542013-08-04 13:51:17 +02002307XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002308 _elementJustOpened( false ),
2309 _firstElement( true ),
2310 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002311 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002312 _textDepth( -1 ),
2313 _processEntities( true ),
2314 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002317 _entityFlag[i] = false;
2318 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 }
2320 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002321 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002322 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002323 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002325 _restrictedEntityFlag[(unsigned char)'&'] = true;
2326 _restrictedEntityFlag[(unsigned char)'<'] = true;
2327 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002328 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002329}
2330
2331
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002332void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002333{
2334 va_list va;
2335 va_start( va, format );
2336
Lee Thomason624d43f2012-10-12 10:58:48 -07002337 if ( _fp ) {
2338 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 }
2340 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002341 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 // Close out and re-start the va-args
2343 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002344 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002346 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002347 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002348 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002350 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002351}
2352
2353
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002354void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 for( int i=0; i<depth; ++i ) {
2357 Print( " " );
2358 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002359}
2360
2361
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002362void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 // Look for runs of bytes between entities to print.
2365 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002366
Lee Thomason624d43f2012-10-12 10:58:48 -07002367 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002368 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002370 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 // Remember, char is sometimes signed. (How many times has that bitten me?)
2372 if ( *q > 0 && *q < ENTITY_RANGE ) {
2373 // Check for entities. If one is found, flush
2374 // the stream up until the entity, write the
2375 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002376 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002378 const size_t delta = q - p;
2379 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002380 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002381 Print( "%.*s", toPrint, p );
2382 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002384 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 for( int i=0; i<NUM_ENTITIES; ++i ) {
2386 if ( entities[i].value == *q ) {
2387 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002388 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 break;
2390 }
2391 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002392 if ( !entityPatternPrinted ) {
2393 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2394 TIXMLASSERT( false );
2395 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 ++p;
2397 }
2398 }
2399 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002400 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002401 }
2402 }
2403 // Flush the remaining string. This will be the entire
2404 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002405 TIXMLASSERT( p <= q );
2406 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 Print( "%s", p );
2408 }
Lee Thomason857b8682012-01-25 17:50:25 -08002409}
2410
U-Stream\Leeae25a442012-02-17 17:48:16 -08002411
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002412void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002415 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 -07002416 Print( "%s", bom );
2417 }
2418 if ( writeDec ) {
2419 PushDeclaration( "xml version=\"1.0\"" );
2420 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002421}
2422
2423
Uli Kusterer593a33d2014-02-01 12:48:51 +01002424void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002425{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002426 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002427 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002428
Uli Kusterer593a33d2014-02-01 12:48:51 +01002429 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002431 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002432 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002433 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002434 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002435
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002437 _elementJustOpened = true;
2438 _firstElement = false;
2439 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002440}
2441
2442
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002443void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002444{
Lee Thomason624d43f2012-10-12 10:58:48 -07002445 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 Print( " %s=\"", name );
2447 PrintString( value, false );
2448 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002449}
2450
2451
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002452void XMLPrinter::PushAttribute( const char* name, int v )
2453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 char buf[BUF_SIZE];
2455 XMLUtil::ToStr( v, buf, BUF_SIZE );
2456 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002457}
2458
2459
2460void XMLPrinter::PushAttribute( const char* name, unsigned v )
2461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 char buf[BUF_SIZE];
2463 XMLUtil::ToStr( v, buf, BUF_SIZE );
2464 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002465}
2466
2467
Lee Thomason51c12712016-06-04 20:18:49 -07002468void XMLPrinter::PushAttribute(const char* name, int64_t v)
2469{
2470 char buf[BUF_SIZE];
2471 XMLUtil::ToStr(v, buf, BUF_SIZE);
2472 PushAttribute(name, buf);
2473}
2474
2475
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002476void XMLPrinter::PushAttribute( const char* name, bool v )
2477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 char buf[BUF_SIZE];
2479 XMLUtil::ToStr( v, buf, BUF_SIZE );
2480 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002481}
2482
2483
2484void XMLPrinter::PushAttribute( const char* name, double v )
2485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002486 char buf[BUF_SIZE];
2487 XMLUtil::ToStr( v, buf, BUF_SIZE );
2488 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002489}
2490
2491
Uli Kustererca412e82014-02-01 13:35:05 +01002492void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002493{
Lee Thomason624d43f2012-10-12 10:58:48 -07002494 --_depth;
2495 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002496
Lee Thomason624d43f2012-10-12 10:58:48 -07002497 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002498 Print( "/>" );
2499 }
2500 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002501 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002503 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 }
2505 Print( "</%s>", name );
2506 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002507
Lee Thomason624d43f2012-10-12 10:58:48 -07002508 if ( _textDepth == _depth ) {
2509 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002510 }
Uli Kustererca412e82014-02-01 13:35:05 +01002511 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002512 Print( "\n" );
2513 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002515}
2516
2517
Dmitry-Mea092bc12014-12-23 17:57:05 +03002518void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002519{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002520 if ( !_elementJustOpened ) {
2521 return;
2522 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002523 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002525}
2526
2527
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002528void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002529{
Lee Thomason624d43f2012-10-12 10:58:48 -07002530 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002531
Dmitry-Mea092bc12014-12-23 17:57:05 +03002532 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002534 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 }
2536 else {
2537 PrintString( text, true );
2538 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002539}
2540
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002541void XMLPrinter::PushText( int64_t value )
2542{
2543 char buf[BUF_SIZE];
2544 XMLUtil::ToStr( value, buf, BUF_SIZE );
2545 PushText( buf, false );
2546}
2547
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002548void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002549{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002550 char buf[BUF_SIZE];
2551 XMLUtil::ToStr( value, buf, BUF_SIZE );
2552 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002553}
2554
2555
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002556void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 char buf[BUF_SIZE];
2559 XMLUtil::ToStr( value, buf, BUF_SIZE );
2560 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002561}
2562
2563
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002564void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002566 char buf[BUF_SIZE];
2567 XMLUtil::ToStr( value, buf, BUF_SIZE );
2568 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002569}
2570
2571
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002572void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002574 char buf[BUF_SIZE];
2575 XMLUtil::ToStr( value, buf, BUF_SIZE );
2576 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002577}
2578
2579
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002580void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 char buf[BUF_SIZE];
2583 XMLUtil::ToStr( value, buf, BUF_SIZE );
2584 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002585}
2586
Lee Thomason5cae8972012-01-24 18:03:07 -08002587
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002588void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002589{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002590 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002591 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002592 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002593 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002594 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002595 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002597}
Lee Thomason751da522012-02-10 08:50:51 -08002598
2599
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002600void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002601{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002602 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002603 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002605 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002606 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002607 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002608 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002609}
2610
2611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002612void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002613{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002614 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002615 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002616 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002617 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002618 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002619 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002620 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002621}
2622
2623
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002624bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002625{
Lee Thomason624d43f2012-10-12 10:58:48 -07002626 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 if ( doc.HasBOM() ) {
2628 PushHeader( true, false );
2629 }
2630 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002631}
2632
2633
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002634bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002635{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002636 const XMLElement* parentElem = 0;
2637 if ( element.Parent() ) {
2638 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002639 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002640 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002641 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002642 while ( attribute ) {
2643 PushAttribute( attribute->Name(), attribute->Value() );
2644 attribute = attribute->Next();
2645 }
2646 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002647}
2648
2649
Uli Kustererca412e82014-02-01 13:35:05 +01002650bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002651{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002652 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002653 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002654}
2655
2656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002657bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002658{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002659 PushText( text.Value(), text.CData() );
2660 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002661}
2662
2663
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002664bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002665{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 PushComment( comment.Value() );
2667 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002668}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002669
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002670bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002671{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 PushDeclaration( declaration.Value() );
2673 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002674}
2675
2676
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002677bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002679 PushUnknown( unknown.Value() );
2680 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002681}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002682
Lee Thomason685b8952012-11-12 13:00:06 -08002683} // namespace tinyxml2
2684