blob: 87c1a99f6800fe98889ca39b4f917d4e94799761 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300681 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000682 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += xmlHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += commentHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p += cdataHeaderLen;
695 text->SetCData( true );
696 }
697 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += dtdHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += elementHeaderLen;
706 }
707 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000711 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Dmitry-Me02384662015-03-03 16:02:13 +0300714 TIXMLASSERT( returnNode );
715 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 *node = returnNode;
717 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718}
719
720
Lee Thomason751da522012-02-10 08:50:51 -0800721bool XMLDocument::Accept( XMLVisitor* visitor ) const
722{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300723 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( visitor->VisitEnter( *this ) ) {
725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
726 if ( !node->Accept( visitor ) ) {
727 break;
728 }
729 }
730 }
731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735// --------- XMLNode ----------- //
736
737XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _document( doc ),
739 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000740 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200742 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700743 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200744 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746}
747
748
749XMLNode::~XMLNode()
750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( _parent ) {
753 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755}
756
Michael Daumling21626882013-10-22 17:03:37 +0200757const char* XMLNode::Value() const
758{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300759 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530760 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530761 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200762 return _value.GetStr();
763}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800765void XMLNode::SetValue( const char* str, bool staticMem )
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800773}
774
775
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800776void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800777{
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300779 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300780 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800783}
784
785
786void XMLNode::Unlink( XMLNode* child )
787{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300788 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300789 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300790 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 if ( child == _firstChild ) {
792 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 if ( child == _lastChild ) {
795 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 }
Lee Thomasond923c672012-01-23 08:44:25 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 if ( child->_prev ) {
799 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 if ( child->_next ) {
802 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700804 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805}
806
807
U-Stream\Leeae25a442012-02-17 17:48:16 -0800808void XMLNode::DeleteChild( XMLNode* node )
809{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300810 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300811 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100813 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800815}
816
817
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800818XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
819{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300820 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300821 if ( addThis->_document != _document ) {
822 TIXMLASSERT( false );
823 return 0;
824 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800825 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 if ( _lastChild ) {
828 TIXMLASSERT( _firstChild );
829 TIXMLASSERT( _lastChild->_next == 0 );
830 _lastChild->_next = addThis;
831 addThis->_prev = _lastChild;
832 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
836 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 TIXMLASSERT( _firstChild == 0 );
838 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800839
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 addThis->_prev = 0;
841 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800845}
846
847
Lee Thomason1ff38e02012-02-14 18:18:16 -0800848XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
849{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300850 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 if ( addThis->_document != _document ) {
852 TIXMLASSERT( false );
853 return 0;
854 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800855 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( _firstChild ) {
858 TIXMLASSERT( _lastChild );
859 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 _firstChild->_prev = addThis;
862 addThis->_next = _firstChild;
863 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800864
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 }
867 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 TIXMLASSERT( _lastChild == 0 );
869 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 addThis->_prev = 0;
872 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400875 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876}
877
878
879XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
880{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300881 TIXMLASSERT( addThis );
882 if ( addThis->_document != _document ) {
883 TIXMLASSERT( false );
884 return 0;
885 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700886
Dmitry-Meabb2d042014-12-09 12:59:31 +0300887 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300890 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return 0;
892 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 // The last node or the only node.
896 return InsertEndChild( addThis );
897 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800898 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 addThis->_prev = afterThis;
900 addThis->_next = afterThis->_next;
901 afterThis->_next->_prev = addThis;
902 afterThis->_next = addThis;
903 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905}
906
907
908
909
Dmitry-Me886ad972015-07-22 11:00:51 +0300910const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800911{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300912 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300913 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300915 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 }
917 }
918 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800919}
920
921
Dmitry-Me886ad972015-07-22 11:00:51 +0300922const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800923{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300924 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300925 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300937 const XMLElement* element = node->ToElementWithName( name );
938 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800943}
944
945
Dmitry-Me886ad972015-07-22 11:00:51 +0300946const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300948 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300949 const XMLElement* element = node->ToElementWithName( name );
950 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400951 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 }
954 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
kezenator4f756162016-11-29 19:46:27 +1000958char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 // This is a recursive method, but thinking about it "at the current level"
961 // it is a pretty simple flat list:
962 // <foo/>
963 // <!-- comment -->
964 //
965 // With a special case:
966 // <foo>
967 // </foo>
968 // <!-- comment -->
969 //
970 // Where the closing element (/foo) *must* be the next thing after the opening
971 // element, and the names must match. BUT the tricky bit is that the closing
972 // element will be read by the child.
973 //
974 // 'endTag' is the end tag for this node, it is returned by a call to a child.
975 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 while( p && *p ) {
978 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800979
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300981 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300982 if ( node == 0 ) {
983 break;
984 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985
kezenatore3531812016-11-29 19:49:07 +1000986 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000987
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000989 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400991 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000993 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 break;
996 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530998 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530999 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001000 // Declarations are only allowed at document level
1001 bool wellLocated = ( ToDocument() != 0 );
1002 if ( wellLocated ) {
1003 // Multiple declarations are allowed but all declarations
1004 // must occur before anything else
1005 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1006 if ( !existingNode->ToDeclaration() ) {
1007 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301008 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001009 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301010 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001011 }
1012 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001013 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001014 DeleteNode( node );
1015 break;
1016 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301017 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301018
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001019 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001021 // We read the end tag. Return it to the parent.
1022 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1023 if ( parentEnd ) {
1024 ele->_value.TransferTo( parentEnd );
1025 }
1026 node->_memPool->SetTracked(); // created and then immediately deleted.
1027 DeleteNode( node );
1028 return p;
1029 }
1030
1031 // Handle an end tag returned to this level.
1032 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001033 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001034 if ( endTag.Empty() ) {
1035 if ( ele->ClosingType() == XMLElement::OPEN ) {
1036 mismatch = true;
1037 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001039 else {
1040 if ( ele->ClosingType() != XMLElement::OPEN ) {
1041 mismatch = true;
1042 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001043 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001044 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001047 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001048 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001049 DeleteNode( node );
1050 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001051 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
JayXondbfdd8f2014-12-12 20:07:14 -05001053 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 }
1055 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001056}
1057
Dmitry-Mee3225b12014-09-03 11:03:11 +04001058void XMLNode::DeleteNode( XMLNode* node )
1059{
1060 if ( node == 0 ) {
1061 return;
1062 }
1063 MemPool* pool = node->_memPool;
1064 node->~XMLNode();
1065 pool->Free( node );
1066}
1067
Lee Thomason3cebdc42015-01-05 17:16:28 -08001068void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001069{
1070 TIXMLASSERT( insertThis );
1071 TIXMLASSERT( insertThis->_document == _document );
1072
1073 if ( insertThis->_parent )
1074 insertThis->_parent->Unlink( insertThis );
1075 else
1076 insertThis->_memPool->SetTracked();
1077}
1078
Dmitry-Meecb9b072016-10-12 16:44:59 +03001079const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1080{
1081 const XMLElement* element = this->ToElement();
1082 if ( element == 0 ) {
1083 return 0;
1084 }
1085 if ( name == 0 ) {
1086 return element;
1087 }
1088 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1089 return element;
1090 }
1091 return 0;
1092}
1093
Lee Thomason5492a1c2012-01-23 15:32:10 -08001094// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001095char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 const char* start = p;
1098 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001099 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001101 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 }
1103 return p;
1104 }
1105 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1107 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001108 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001110
kezenator4f756162016-11-29 19:46:27 +10001111 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( p && *p ) {
1113 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001114 }
1115 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001116 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 }
1118 }
1119 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001120}
1121
1122
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1129 text->SetCData( this->CData() );
1130 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
1134bool XMLText::ShallowEqual( const XMLNode* compare ) const
1135{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001136 const XMLText* text = compare->ToText();
1137 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001138}
1139
1140
Lee Thomason56bdd022012-02-09 18:16:58 -08001141bool XMLText::Accept( XMLVisitor* visitor ) const
1142{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001143 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001145}
1146
1147
Lee Thomason3f57d272012-01-11 15:30:03 -08001148// --------- XMLComment ---------- //
1149
Lee Thomasone4422302012-01-20 17:59:50 -08001150XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001151{
1152}
1153
1154
Lee Thomasonce0763e2012-01-11 15:43:54 -08001155XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001156{
Lee Thomason3f57d272012-01-11 15:30:03 -08001157}
1158
1159
kezenator4f756162016-11-29 19:46:27 +10001160char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 // Comment parses as text.
1163 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001164 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001166 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 }
1168 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001169}
1170
1171
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 }
1177 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1178 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001179}
1180
1181
1182bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1183{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001184 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001185 const XMLComment* comment = compare->ToComment();
1186 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001187}
1188
1189
Lee Thomason751da522012-02-10 08:50:51 -08001190bool XMLComment::Accept( XMLVisitor* visitor ) const
1191{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001192 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001194}
Lee Thomason56bdd022012-02-09 18:16:58 -08001195
1196
Lee Thomason50f97b22012-02-11 16:33:40 -08001197// --------- XMLDeclaration ---------- //
1198
1199XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1200{
1201}
1202
1203
1204XMLDeclaration::~XMLDeclaration()
1205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001207}
1208
1209
kezenator4f756162016-11-29 19:46:27 +10001210char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 // Declaration parses as text.
1213 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001214 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001216 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
1218 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001219}
1220
1221
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001222XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 }
1227 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1228 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001229}
1230
1231
1232bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1233{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001234 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001235 const XMLDeclaration* declaration = compare->ToDeclaration();
1236 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001237}
1238
1239
1240
Lee Thomason50f97b22012-02-11 16:33:40 -08001241bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1242{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001243 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247// --------- XMLUnknown ---------- //
1248
1249XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1250{
1251}
1252
1253
1254XMLUnknown::~XMLUnknown()
1255{
1256}
1257
1258
kezenator4f756162016-11-29 19:46:27 +10001259char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 // Unknown parses as text.
1262 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001263
kezenator4f756162016-11-29 19:46:27 +10001264 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001266 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 }
1268 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001269}
1270
1271
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001272XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 }
1277 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1278 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001279}
1280
1281
1282bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1283{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001284 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001285 const XMLUnknown* unknown = compare->ToUnknown();
1286 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001287}
1288
1289
Lee Thomason50f97b22012-02-11 16:33:40 -08001290bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1291{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001292 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001294}
1295
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001296// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001297
1298const char* XMLAttribute::Name() const
1299{
1300 return _name.GetStr();
1301}
1302
1303const char* XMLAttribute::Value() const
1304{
1305 return _value.GetStr();
1306}
1307
kezenator4f756162016-11-29 19:46:27 +10001308char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !p || !*p ) {
1313 return 0;
1314 }
Lee Thomason22aead12012-01-23 13:29:35 -08001315
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001317 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001318 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return 0;
1320 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001321
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001323 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( *p != '\"' && *p != '\'' ) {
1325 return 0;
1326 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001327
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 char endTag[2] = { *p, 0 };
1329 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001330
kezenator4f756162016-11-29 19:46:27 +10001331 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001333}
1334
1335
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001336void XMLAttribute::SetName( const char* n )
1337{
Lee Thomason624d43f2012-10-12 10:58:48 -07001338 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001339}
1340
1341
Lee Thomason2fa81722012-11-09 12:37:46 -08001342XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001345 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001348}
1349
1350
Lee Thomason2fa81722012-11-09 12:37:46 -08001351XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001354 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 }
1356 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001357}
1358
1359
Lee Thomason51c12712016-06-04 20:18:49 -07001360XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1361{
1362 if (XMLUtil::ToInt64(Value(), value)) {
1363 return XML_SUCCESS;
1364 }
1365 return XML_WRONG_ATTRIBUTE_TYPE;
1366}
1367
1368
Lee Thomason2fa81722012-11-09 12:37:46 -08001369XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001372 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 }
1374 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001375}
1376
1377
Lee Thomason2fa81722012-11-09 12:37:46 -08001378XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001381 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 }
1383 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
Lee Thomason2fa81722012-11-09 12:37:46 -08001387XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001390 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 }
1392 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001393}
1394
1395
1396void XMLAttribute::SetAttribute( const char* v )
1397{
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001399}
1400
1401
Lee Thomason1ff38e02012-02-14 18:18:16 -08001402void XMLAttribute::SetAttribute( int v )
1403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001407}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001408
1409
1410void XMLAttribute::SetAttribute( unsigned v )
1411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 char buf[BUF_SIZE];
1413 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001415}
1416
1417
Lee Thomason51c12712016-06-04 20:18:49 -07001418void XMLAttribute::SetAttribute(int64_t v)
1419{
1420 char buf[BUF_SIZE];
1421 XMLUtil::ToStr(v, buf, BUF_SIZE);
1422 _value.SetStr(buf);
1423}
1424
1425
1426
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427void XMLAttribute::SetAttribute( bool v )
1428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 char buf[BUF_SIZE];
1430 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001432}
1433
1434void XMLAttribute::SetAttribute( double v )
1435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 char buf[BUF_SIZE];
1437 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439}
1440
1441void XMLAttribute::SetAttribute( float v )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 char buf[BUF_SIZE];
1444 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446}
1447
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001448
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001449// --------- XMLElement ---------- //
1450XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _closingType( 0 ),
1452 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001453{
1454}
1455
1456
1457XMLElement::~XMLElement()
1458{
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 while( _rootAttribute ) {
1460 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001461 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464}
1465
1466
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001467const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1468{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001469 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1471 return a;
1472 }
1473 }
1474 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001475}
1476
1477
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001478const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001479{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 const XMLAttribute* a = FindAttribute( name );
1481 if ( !a ) {
1482 return 0;
1483 }
1484 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1485 return a->Value();
1486 }
1487 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001488}
1489
Josh Wittnercf3dd092016-10-11 18:57:17 -07001490int XMLElement::IntAttribute(const char* name, int defaultValue) const
1491{
1492 int i = defaultValue;
1493 QueryIntAttribute(name, &i);
1494 return i;
1495}
1496
1497unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1498{
1499 unsigned i = defaultValue;
1500 QueryUnsignedAttribute(name, &i);
1501 return i;
1502}
1503
1504int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1505{
1506 int64_t i = defaultValue;
1507 QueryInt64Attribute(name, &i);
1508 return i;
1509}
1510
1511bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1512{
1513 bool b = defaultValue;
1514 QueryBoolAttribute(name, &b);
1515 return b;
1516}
1517
1518double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1519{
1520 double d = defaultValue;
1521 QueryDoubleAttribute(name, &d);
1522 return d;
1523}
1524
1525float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1526{
1527 float f = defaultValue;
1528 QueryFloatAttribute(name, &f);
1529 return f;
1530}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001531
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001532const char* XMLElement::GetText() const
1533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001535 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001538}
1539
1540
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001541void XMLElement::SetText( const char* inText )
1542{
Uli Kusterer869bb592014-01-21 01:36:16 +01001543 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001544 FirstChild()->SetValue( inText );
1545 else {
1546 XMLText* theText = GetDocument()->NewText( inText );
1547 InsertFirstChild( theText );
1548 }
1549}
1550
Lee Thomason5bb2d802014-01-24 10:42:57 -08001551
1552void XMLElement::SetText( int v )
1553{
1554 char buf[BUF_SIZE];
1555 XMLUtil::ToStr( v, buf, BUF_SIZE );
1556 SetText( buf );
1557}
1558
1559
1560void XMLElement::SetText( unsigned v )
1561{
1562 char buf[BUF_SIZE];
1563 XMLUtil::ToStr( v, buf, BUF_SIZE );
1564 SetText( buf );
1565}
1566
1567
Lee Thomason51c12712016-06-04 20:18:49 -07001568void XMLElement::SetText(int64_t v)
1569{
1570 char buf[BUF_SIZE];
1571 XMLUtil::ToStr(v, buf, BUF_SIZE);
1572 SetText(buf);
1573}
1574
1575
1576void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001577{
1578 char buf[BUF_SIZE];
1579 XMLUtil::ToStr( v, buf, BUF_SIZE );
1580 SetText( buf );
1581}
1582
1583
1584void XMLElement::SetText( float v )
1585{
1586 char buf[BUF_SIZE];
1587 XMLUtil::ToStr( v, buf, BUF_SIZE );
1588 SetText( buf );
1589}
1590
1591
1592void XMLElement::SetText( double v )
1593{
1594 char buf[BUF_SIZE];
1595 XMLUtil::ToStr( v, buf, BUF_SIZE );
1596 SetText( buf );
1597}
1598
1599
MortenMacFly4ee49f12013-01-14 20:03:14 +01001600XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001603 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001604 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 return XML_SUCCESS;
1606 }
1607 return XML_CAN_NOT_CONVERT_TEXT;
1608 }
1609 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001610}
1611
1612
MortenMacFly4ee49f12013-01-14 20:03:14 +01001613XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001616 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001617 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 return XML_SUCCESS;
1619 }
1620 return XML_CAN_NOT_CONVERT_TEXT;
1621 }
1622 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001623}
1624
1625
Lee Thomason51c12712016-06-04 20:18:49 -07001626XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1627{
1628 if (FirstChild() && FirstChild()->ToText()) {
1629 const char* t = FirstChild()->Value();
1630 if (XMLUtil::ToInt64(t, ival)) {
1631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
1636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001642 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
MortenMacFly4ee49f12013-01-14 20:03:14 +01001652XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001655 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001656 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001662}
1663
1664
MortenMacFly4ee49f12013-01-14 20:03:14 +01001665XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001666{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001667 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001668 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001669 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return XML_SUCCESS;
1671 }
1672 return XML_CAN_NOT_CONVERT_TEXT;
1673 }
1674 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001675}
1676
Josh Wittnercf3dd092016-10-11 18:57:17 -07001677int XMLElement::IntText(int defaultValue) const
1678{
1679 int i = defaultValue;
1680 QueryIntText(&i);
1681 return i;
1682}
1683
1684unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1685{
1686 unsigned i = defaultValue;
1687 QueryUnsignedText(&i);
1688 return i;
1689}
1690
1691int64_t XMLElement::Int64Text(int64_t defaultValue) const
1692{
1693 int64_t i = defaultValue;
1694 QueryInt64Text(&i);
1695 return i;
1696}
1697
1698bool XMLElement::BoolText(bool defaultValue) const
1699{
1700 bool b = defaultValue;
1701 QueryBoolText(&b);
1702 return b;
1703}
1704
1705double XMLElement::DoubleText(double defaultValue) const
1706{
1707 double d = defaultValue;
1708 QueryDoubleText(&d);
1709 return d;
1710}
1711
1712float XMLElement::FloatText(float defaultValue) const
1713{
1714 float f = defaultValue;
1715 QueryFloatText(&f);
1716 return f;
1717}
Lee Thomason21be8822012-07-15 17:27:22 -07001718
1719
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001720XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 XMLAttribute* last = 0;
1723 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1728 break;
1729 }
1730 }
1731 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001732 attrib = CreateAttribute();
1733 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001735 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 }
1738 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001739 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 }
1742 attrib->SetName( name );
1743 }
1744 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001745}
1746
1747
U-Stream\Leeae25a442012-02-17 17:48:16 -08001748void XMLElement::DeleteAttribute( const char* name )
1749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1753 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 }
1756 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001759 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 break;
1761 }
1762 prev = a;
1763 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001764}
1765
1766
kezenator4f756162016-11-29 19:46:27 +10001767char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 const char* start = p;
1770 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 // Read the attributes.
1773 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001774 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001775 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001776 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 return 0;
1778 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001779
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001781 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001782 XMLAttribute* attrib = CreateAttribute();
1783 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001784 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001785
kezenatorec694152016-11-26 17:21:43 +10001786 int attrLineNum = attrib->_parseLineNum;
1787
kezenator4f756162016-11-29 19:46:27 +10001788 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001790 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001791 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 return 0;
1793 }
1794 // There is a minor bug here: if the attribute in the source xml
1795 // document is duplicated, it will not be detected and the
1796 // attribute will be doubly added. However, tracking the 'prevAttribute'
1797 // avoids re-scanning the attribute list. Preferring performance for
1798 // now, may reconsider in the future.
1799 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001800 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 }
1803 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001804 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
1807 prevAttribute = attrib;
1808 }
1809 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 else if ( *p == '>' ) {
1811 ++p;
1812 break;
1813 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001814 // end of the tag
1815 else if ( *p == '/' && *(p+1) == '>' ) {
1816 _closingType = CLOSED;
1817 return p+2; // done; sealed element.
1818 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 else {
kezenatorec694152016-11-26 17:21:43 +10001820 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 return 0;
1822 }
1823 }
1824 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001825}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001826
Dmitry-Mee3225b12014-09-03 11:03:11 +04001827void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1828{
1829 if ( attribute == 0 ) {
1830 return;
1831 }
1832 MemPool* pool = attribute->_memPool;
1833 attribute->~XMLAttribute();
1834 pool->Free( attribute );
1835}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001836
Dmitry-Mea60caa22016-11-22 18:28:08 +03001837XMLAttribute* XMLElement::CreateAttribute()
1838{
1839 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1840 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001841 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001842 attrib->_memPool = &_document->_attributePool;
1843 attrib->_memPool->SetTracked();
1844 return attrib;
1845}
1846
Lee Thomason67d61312012-01-24 16:01:51 -08001847//
1848// <ele></ele>
1849// <ele>foo<b>bar</b></ele>
1850//
kezenator4f756162016-11-29 19:46:27 +10001851char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001852{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001854 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001855
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 // The closing element is the </element> form. It is
1857 // parsed just like a regular element then deleted from
1858 // the DOM.
1859 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 ++p;
1862 }
Lee Thomason67d61312012-01-24 16:01:51 -08001863
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 p = _value.ParseName( p );
1865 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 return 0;
1867 }
Lee Thomason67d61312012-01-24 16:01:51 -08001868
kezenator4f756162016-11-29 19:46:27 +10001869 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 return p;
1872 }
Lee Thomason67d61312012-01-24 16:01:51 -08001873
kezenator4f756162016-11-29 19:46:27 +10001874 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001876}
1877
1878
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001879
1880XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1881{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 }
1885 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1886 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1887 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1888 }
1889 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001890}
1891
1892
1893bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1894{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001895 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001897 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001898
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 const XMLAttribute* a=FirstAttribute();
1900 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001901
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 while ( a && b ) {
1903 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1904 return false;
1905 }
1906 a = a->Next();
1907 b = b->Next();
1908 }
1909 if ( a || b ) {
1910 // different count
1911 return false;
1912 }
1913 return true;
1914 }
1915 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916}
1917
1918
Lee Thomason751da522012-02-10 08:50:51 -08001919bool XMLElement::Accept( XMLVisitor* visitor ) const
1920{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001921 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1924 if ( !node->Accept( visitor ) ) {
1925 break;
1926 }
1927 }
1928 }
1929 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001930}
Lee Thomason56bdd022012-02-09 18:16:58 -08001931
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001932
Lee Thomason3f57d272012-01-11 15:30:03 -08001933// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001934
1935// Warning: List must match 'enum XMLError'
1936const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1937 "XML_SUCCESS",
1938 "XML_NO_ATTRIBUTE",
1939 "XML_WRONG_ATTRIBUTE_TYPE",
1940 "XML_ERROR_FILE_NOT_FOUND",
1941 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1942 "XML_ERROR_FILE_READ_ERROR",
1943 "XML_ERROR_ELEMENT_MISMATCH",
1944 "XML_ERROR_PARSING_ELEMENT",
1945 "XML_ERROR_PARSING_ATTRIBUTE",
1946 "XML_ERROR_IDENTIFYING_TAG",
1947 "XML_ERROR_PARSING_TEXT",
1948 "XML_ERROR_PARSING_CDATA",
1949 "XML_ERROR_PARSING_COMMENT",
1950 "XML_ERROR_PARSING_DECLARATION",
1951 "XML_ERROR_PARSING_UNKNOWN",
1952 "XML_ERROR_EMPTY_DOCUMENT",
1953 "XML_ERROR_MISMATCHED_ELEMENT",
1954 "XML_ERROR_PARSING",
1955 "XML_CAN_NOT_CONVERT_TEXT",
1956 "XML_NO_TEXT_NODE"
1957};
1958
1959
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001960XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 _writeBOM( false ),
1963 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001964 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001965 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001966 _errorLineNum( 0 ),
1967 _charBuffer( 0 ),
1968 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001969{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001970 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1971 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001972}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001973
1974
Lee Thomason3f57d272012-01-11 15:30:03 -08001975XMLDocument::~XMLDocument()
1976{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001977 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001978}
1979
1980
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001981void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001982{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001983 DeleteChildren();
1984
Dmitry-Meab37df82014-11-28 12:08:36 +03001985#ifdef DEBUG
1986 const bool hadError = Error();
1987#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001988 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001989
Lee Thomason624d43f2012-10-12 10:58:48 -07001990 delete [] _charBuffer;
1991 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001992
1993#if 0
1994 _textPool.Trace( "text" );
1995 _elementPool.Trace( "element" );
1996 _commentPool.Trace( "comment" );
1997 _attributePool.Trace( "attribute" );
1998#endif
1999
2000#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002001 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002002 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2003 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2004 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2005 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2006 }
2007#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002008}
2009
Lee Thomason3f57d272012-01-11 15:30:03 -08002010
Lee Thomason2c85a712012-01-31 08:24:24 -08002011XMLElement* XMLDocument::NewElement( const char* name )
2012{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002013 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _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-Me2aebfb72017-02-27 15:53:40 +03002021 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 comment->SetValue( str );
2023 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002024}
2025
2026
2027XMLText* XMLDocument::NewText( const char* str )
2028{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002029 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 text->SetValue( str );
2031 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002032}
2033
2034
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002035XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2036{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002037 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2039 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002040}
2041
2042
2043XMLUnknown* XMLDocument::NewUnknown( const char* str )
2044{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002045 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 unk->SetValue( str );
2047 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002048}
2049
Dmitry-Me01578db2014-08-19 10:18:48 +04002050static FILE* callfopen( const char* filepath, const char* mode )
2051{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002052 TIXMLASSERT( filepath );
2053 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002054#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2055 FILE* fp = 0;
2056 errno_t err = fopen_s( &fp, filepath, mode );
2057 if ( err ) {
2058 return 0;
2059 }
2060#else
2061 FILE* fp = fopen( filepath, mode );
2062#endif
2063 return fp;
2064}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002065
2066void XMLDocument::DeleteNode( XMLNode* node ) {
2067 TIXMLASSERT( node );
2068 TIXMLASSERT(node->_document == this );
2069 if (node->_parent) {
2070 node->_parent->DeleteChild( node );
2071 }
2072 else {
2073 // Isn't in the tree.
2074 // Use the parent delete.
2075 // Also, we need to mark it tracked: we 'know'
2076 // it was never used.
2077 node->_memPool->SetTracked();
2078 // Call the static XMLNode version:
2079 XMLNode::DeleteNode(node);
2080 }
2081}
2082
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002083
Lee Thomason2fa81722012-11-09 12:37:46 -08002084XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002085{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002086 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002087 FILE* fp = callfopen( filename, "rb" );
2088 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002089 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 }
2092 LoadFile( fp );
2093 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002095}
2096
Dmitry-Me901fed52015-09-25 10:29:51 +03002097// This is likely overengineered template art to have a check that unsigned long value incremented
2098// by one still fits into size_t. If size_t type is larger than unsigned long type
2099// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2100// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2101// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2102// types sizes relate to each other.
2103template
2104<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2105struct LongFitsIntoSizeTMinusOne {
2106 static bool Fits( unsigned long value )
2107 {
2108 return value < (size_t)-1;
2109 }
2110};
2111
2112template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002113struct LongFitsIntoSizeTMinusOne<false> {
2114 static bool Fits( unsigned long )
2115 {
2116 return true;
2117 }
2118};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002119
Lee Thomason2fa81722012-11-09 12:37:46 -08002120XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002121{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002122 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002123
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002124 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002125 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002126 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002127 return _errorID;
2128 }
2129
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002131 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002133 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002134 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002135 return _errorID;
2136 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002137 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002138
Dmitry-Me901fed52015-09-25 10:29:51 +03002139 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002140 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002141 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002142 return _errorID;
2143 }
2144
Dmitry-Me72801b82015-05-07 09:41:39 +03002145 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002146 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002149
Dmitry-Me72801b82015-05-07 09:41:39 +03002150 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002151 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 _charBuffer = new char[size+1];
2153 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002155 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002158
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002160
Dmitry-Me97476b72015-01-01 16:15:57 +03002161 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002163}
2164
2165
Lee Thomason2fa81722012-11-09 12:37:46 -08002166XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002167{
Dmitry-Me01578db2014-08-19 10:18:48 +04002168 FILE* fp = callfopen( filename, "w" );
2169 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002170 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 }
2173 SaveFile(fp, compact);
2174 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002176}
2177
2178
Lee Thomason2fa81722012-11-09 12:37:46 -08002179XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002180{
Ant Mitchell189198f2015-03-24 16:20:36 +00002181 // Clear any error from the last save, otherwise it will get reported
2182 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002183 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 XMLPrinter stream( fp, compact );
2185 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187}
2188
Lee Thomason1ff38e02012-02-14 18:18:16 -08002189
Lee Thomason2fa81722012-11-09 12:37:46 -08002190XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002191{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002192 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002193
Lee Thomason82d32002014-02-21 22:47:18 -08002194 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002195 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002196 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 }
2198 if ( len == (size_t)(-1) ) {
2199 len = strlen( p );
2200 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002201 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 _charBuffer = new char[ len+1 ];
2203 memcpy( _charBuffer, p, len );
2204 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002205
Dmitry-Me97476b72015-01-01 16:15:57 +03002206 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002207 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002208 // clean up now essentially dangling memory.
2209 // and the parse fail can put objects in the
2210 // pools that are dead and inaccessible.
2211 DeleteChildren();
2212 _elementPool.Clear();
2213 _attributePool.Clear();
2214 _textPool.Clear();
2215 _commentPool.Clear();
2216 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002218}
2219
2220
PKEuS1c5f99e2013-07-06 11:28:39 +02002221void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002222{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002223 if ( streamer ) {
2224 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002226 else {
2227 XMLPrinter stdoutStreamer( stdout );
2228 Accept( &stdoutStreamer );
2229 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002230}
2231
2232
kezenatorec694152016-11-26 17:21:43 +10002233void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002234{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002235 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002237
2238 _errorStr1.Reset();
2239 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002240 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002241
2242 if (str1)
2243 _errorStr1.SetStr(str1);
2244 if (str2)
2245 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002246}
2247
Lee Thomasone90e9012016-12-24 07:34:39 -08002248/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002249{
kezenator5a700712016-11-26 13:54:42 +10002250 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2251 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002252 TIXMLASSERT( errorName && errorName[0] );
2253 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002254}
Lee Thomason5cae8972012-01-24 18:03:07 -08002255
kezenator5a700712016-11-26 13:54:42 +10002256const char* XMLDocument::ErrorName() const
2257{
Lee Thomasone90e9012016-12-24 07:34:39 -08002258 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002259}
2260
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002261void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002262{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002263 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 static const int LEN = 20;
2265 char buf1[LEN] = { 0 };
2266 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002267
Lee Thomason584af572016-09-05 14:14:16 -07002268 if ( !_errorStr1.Empty() ) {
2269 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 }
Lee Thomason584af572016-09-05 14:14:16 -07002271 if ( !_errorStr2.Empty() ) {
2272 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002274
Dmitry-Me2ad43202015-04-16 12:18:58 +03002275 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2276 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2277 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002278 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2279 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002281}
2282
Dmitry-Me97476b72015-01-01 16:15:57 +03002283void XMLDocument::Parse()
2284{
2285 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2286 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002287 _parseCurLineNum = 1;
2288 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002289 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002290 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002291 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002292 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002293 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002294 return;
2295 }
kezenator4f756162016-11-29 19:46:27 +10002296 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002297}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298
PKEuS1bfb9542013-08-04 13:51:17 +02002299XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 _elementJustOpened( false ),
2301 _firstElement( true ),
2302 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002303 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _textDepth( -1 ),
2305 _processEntities( true ),
2306 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002309 _entityFlag[i] = false;
2310 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 }
2312 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002313 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002314 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002315 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002317 _restrictedEntityFlag[(unsigned char)'&'] = true;
2318 _restrictedEntityFlag[(unsigned char)'<'] = true;
2319 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002320 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002321}
2322
2323
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002324void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002325{
2326 va_list va;
2327 va_start( va, format );
2328
Lee Thomason624d43f2012-10-12 10:58:48 -07002329 if ( _fp ) {
2330 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 }
2332 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002333 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002334 // Close out and re-start the va-args
2335 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002336 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002338 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002339 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002340 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002342 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002343}
2344
2345
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002346void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 for( int i=0; i<depth; ++i ) {
2349 Print( " " );
2350 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002351}
2352
2353
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002354void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 // Look for runs of bytes between entities to print.
2357 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002358
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002360 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002362 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 // Remember, char is sometimes signed. (How many times has that bitten me?)
2364 if ( *q > 0 && *q < ENTITY_RANGE ) {
2365 // Check for entities. If one is found, flush
2366 // the stream up until the entity, write the
2367 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002368 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002370 const size_t delta = q - p;
2371 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002372 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002373 Print( "%.*s", toPrint, p );
2374 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002376 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 for( int i=0; i<NUM_ENTITIES; ++i ) {
2378 if ( entities[i].value == *q ) {
2379 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002380 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002381 break;
2382 }
2383 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002384 if ( !entityPatternPrinted ) {
2385 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2386 TIXMLASSERT( false );
2387 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 ++p;
2389 }
2390 }
2391 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002392 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
2394 }
2395 // Flush the remaining string. This will be the entire
2396 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002397 TIXMLASSERT( p <= q );
2398 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002399 Print( "%s", p );
2400 }
Lee Thomason857b8682012-01-25 17:50:25 -08002401}
2402
U-Stream\Leeae25a442012-02-17 17:48:16 -08002403
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002404void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002407 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 -07002408 Print( "%s", bom );
2409 }
2410 if ( writeDec ) {
2411 PushDeclaration( "xml version=\"1.0\"" );
2412 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002413}
2414
2415
Uli Kusterer593a33d2014-02-01 12:48:51 +01002416void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002417{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002418 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002419 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002420
Uli Kusterer593a33d2014-02-01 12:48:51 +01002421 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002423 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002424 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002425 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002426 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002427
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002429 _elementJustOpened = true;
2430 _firstElement = false;
2431 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002432}
2433
2434
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002435void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002436{
Lee Thomason624d43f2012-10-12 10:58:48 -07002437 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 Print( " %s=\"", name );
2439 PrintString( value, false );
2440 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002441}
2442
2443
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002444void XMLPrinter::PushAttribute( const char* name, int v )
2445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 char buf[BUF_SIZE];
2447 XMLUtil::ToStr( v, buf, BUF_SIZE );
2448 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002449}
2450
2451
2452void XMLPrinter::PushAttribute( const char* name, unsigned 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
Lee Thomason51c12712016-06-04 20:18:49 -07002460void XMLPrinter::PushAttribute(const char* name, int64_t v)
2461{
2462 char buf[BUF_SIZE];
2463 XMLUtil::ToStr(v, buf, BUF_SIZE);
2464 PushAttribute(name, buf);
2465}
2466
2467
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002468void XMLPrinter::PushAttribute( const char* name, bool v )
2469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 char buf[BUF_SIZE];
2471 XMLUtil::ToStr( v, buf, BUF_SIZE );
2472 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002473}
2474
2475
2476void XMLPrinter::PushAttribute( const char* name, double 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
Uli Kustererca412e82014-02-01 13:35:05 +01002484void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002485{
Lee Thomason624d43f2012-10-12 10:58:48 -07002486 --_depth;
2487 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002488
Lee Thomason624d43f2012-10-12 10:58:48 -07002489 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 Print( "/>" );
2491 }
2492 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002493 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002494 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002495 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002496 }
2497 Print( "</%s>", name );
2498 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002499
Lee Thomason624d43f2012-10-12 10:58:48 -07002500 if ( _textDepth == _depth ) {
2501 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 }
Uli Kustererca412e82014-02-01 13:35:05 +01002503 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 Print( "\n" );
2505 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002506 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002507}
2508
2509
Dmitry-Mea092bc12014-12-23 17:57:05 +03002510void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002511{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002512 if ( !_elementJustOpened ) {
2513 return;
2514 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002515 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002517}
2518
2519
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002520void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002521{
Lee Thomason624d43f2012-10-12 10:58:48 -07002522 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002523
Dmitry-Mea092bc12014-12-23 17:57:05 +03002524 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002526 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 }
2528 else {
2529 PrintString( text, true );
2530 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002531}
2532
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002533void XMLPrinter::PushText( int64_t value )
2534{
2535 char buf[BUF_SIZE];
2536 XMLUtil::ToStr( value, buf, BUF_SIZE );
2537 PushText( buf, false );
2538}
2539
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002540void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002542 char buf[BUF_SIZE];
2543 XMLUtil::ToStr( value, buf, BUF_SIZE );
2544 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002545}
2546
2547
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002548void XMLPrinter::PushText( unsigned 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( bool 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( float 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( double 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
Lee Thomason5cae8972012-01-24 18:03:07 -08002579
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002580void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002581{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002582 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002585 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002586 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002587 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002588 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002589}
Lee Thomason751da522012-02-10 08:50:51 -08002590
2591
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002592void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002593{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002594 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002595 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002597 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002598 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002599 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002600 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002601}
2602
2603
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002604void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002605{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002606 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002607 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002608 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002609 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002610 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002611 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002613}
2614
2615
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002616bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002617{
Lee Thomason624d43f2012-10-12 10:58:48 -07002618 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 if ( doc.HasBOM() ) {
2620 PushHeader( true, false );
2621 }
2622 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002623}
2624
2625
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002626bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002627{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002628 const XMLElement* parentElem = 0;
2629 if ( element.Parent() ) {
2630 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002631 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002632 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002633 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002634 while ( attribute ) {
2635 PushAttribute( attribute->Name(), attribute->Value() );
2636 attribute = attribute->Next();
2637 }
2638 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002639}
2640
2641
Uli Kustererca412e82014-02-01 13:35:05 +01002642bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002643{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002644 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002645 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002646}
2647
2648
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002649bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 PushText( text.Value(), text.CData() );
2652 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002653}
2654
2655
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002656bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002657{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002658 PushComment( comment.Value() );
2659 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002660}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002661
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002662bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002663{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 PushDeclaration( declaration.Value() );
2665 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002666}
2667
2668
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002669bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002670{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002671 PushUnknown( unknown.Value() );
2672 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002673}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002674
Lee Thomason685b8952012-11-12 13:00:06 -08002675} // namespace tinyxml2
2676