blob: 40f6d82c1d524ff6a5c37bae29d15401d5f7f26e [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
374void XMLUtil::SetBool(const char* writeTrue, const char* writeFalse)
375{
376 static const char* defTrue = "true";
377 static const char* defFalse = "false";
378 if (writeTrue)
Lee Thomasonf458d262016-12-26 22:47:25 -0800379 writeBoolTrue = writeTrue;
Lee Thomasonce667c92016-12-26 16:45:30 -0800380 else
Lee Thomasonf458d262016-12-26 22:47:25 -0800381 writeBoolTrue = defTrue;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382
383 if (writeFalse)
Lee Thomasonf458d262016-12-26 22:47:25 -0800384 writeBoolFalse = writeFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800385 else
Lee Thomasonf458d262016-12-26 22:47:25 -0800386 writeBoolFalse = defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800387}
388
389
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800390const char* XMLUtil::ReadBOM( const char* p, bool* bom )
391{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300392 TIXMLASSERT( p );
393 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 *bom = false;
395 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
396 // Check for BOM:
397 if ( *(pu+0) == TIXML_UTF_LEAD_0
398 && *(pu+1) == TIXML_UTF_LEAD_1
399 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
400 *bom = true;
401 p += 3;
402 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300403 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800405}
406
407
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 const unsigned long BYTE_MASK = 0xBF;
411 const unsigned long BYTE_MARK = 0x80;
412 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800413
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 if (input < 0x80) {
415 *length = 1;
416 }
417 else if ( input < 0x800 ) {
418 *length = 2;
419 }
420 else if ( input < 0x10000 ) {
421 *length = 3;
422 }
423 else if ( input < 0x200000 ) {
424 *length = 4;
425 }
426 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300427 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 return;
429 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800430
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800432
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 // Scary scary fall throughs.
434 switch (*length) {
435 case 4:
436 --output;
437 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
438 input >>= 6;
439 case 3:
440 --output;
441 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
442 input >>= 6;
443 case 2:
444 --output;
445 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
446 input >>= 6;
447 case 1:
448 --output;
449 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100450 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300451 default:
452 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800454}
455
456
457const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 // Presume an entity, and pull it out.
460 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800461
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( *(p+1) == '#' && *(p+2) ) {
463 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300464 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 ptrdiff_t delta = 0;
466 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800467 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800468
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 if ( *(p+2) == 'x' ) {
470 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300471 const char* q = p+3;
472 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800475
Lee Thomason7e67bc82015-01-12 14:05:12 -0800476 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800477
Dmitry-Me9f56e122015-01-12 10:07:54 +0300478 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 return 0;
480 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800481 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 delta = q-p;
484 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800485
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700487 unsigned int digit = 0;
488
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300493 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 }
495 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 }
498 else {
499 return 0;
500 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100501 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300502 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
503 const unsigned int digitScaled = mult * digit;
504 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
505 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300506 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 mult *= 16;
508 --q;
509 }
510 }
511 else {
512 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300513 const char* q = p+2;
514 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800517
Lee Thomason7e67bc82015-01-12 14:05:12 -0800518 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800519
Dmitry-Me9f56e122015-01-12 10:07:54 +0300520 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 return 0;
522 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800523 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800524
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 delta = q-p;
526 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800527
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 while ( *q != '#' ) {
529 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300530 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100531 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300532 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
533 const unsigned int digitScaled = mult * digit;
534 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
535 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 }
537 else {
538 return 0;
539 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300540 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 mult *= 10;
542 --q;
543 }
544 }
545 // convert the UCS to UTF-8
546 ConvertUTF32ToUTF8( ucs, value, length );
547 return p + delta + 1;
548 }
549 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800550}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800551
552
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700553void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
564
565void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
566{
Lee Thomasonce667c92016-12-26 16:45:30 -0800567 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700568}
569
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570/*
571 ToStr() of a number is a very tricky topic.
572 https://github.com/leethomason/tinyxml2/issues/106
573*/
Lee Thomason21be8822012-07-15 17:27:22 -0700574void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
580void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
581{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800582 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700583}
584
585
Lee Thomason51c12712016-06-04 20:18:49 -0700586void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
587{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700588 // horrible syntax trick to make the compiler happy about %lld
589 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700590}
591
592
Lee Thomason21be8822012-07-15 17:27:22 -0700593bool XMLUtil::ToInt( const char* str, int* value )
594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
596 return true;
597 }
598 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700599}
600
601bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
604 return true;
605 }
606 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700607}
608
609bool XMLUtil::ToBool( const char* str, bool* value )
610{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 int ival = 0;
612 if ( ToInt( str, &ival )) {
613 *value = (ival==0) ? false : true;
614 return true;
615 }
616 if ( StringEqual( str, "true" ) ) {
617 *value = true;
618 return true;
619 }
620 else if ( StringEqual( str, "false" ) ) {
621 *value = false;
622 return true;
623 }
624 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700625}
626
627
628bool XMLUtil::ToFloat( const char* str, float* value )
629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
631 return true;
632 }
633 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700634}
635
Lee Thomason51c12712016-06-04 20:18:49 -0700636
Lee Thomason21be8822012-07-15 17:27:22 -0700637bool XMLUtil::ToDouble( const char* str, double* value )
638{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
640 return true;
641 }
642 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700643}
644
645
Lee Thomason51c12712016-06-04 20:18:49 -0700646bool XMLUtil::ToInt64(const char* str, int64_t* value)
647{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700648 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
649 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
650 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700651 return true;
652 }
653 return false;
654}
655
656
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700657char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658{
Dmitry-Me02384662015-03-03 16:02:13 +0300659 TIXMLASSERT( node );
660 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400661 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000662 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000663 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300665 *node = 0;
666 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 return p;
668 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800669
Dmitry-Me962083b2015-05-26 11:38:30 +0300670 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const char* xmlHeader = { "<?" };
672 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 static const int xmlHeaderLen = 2;
678 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300680 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
684 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400685 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300687 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
kezenatorec694152016-11-26 17:21:43 +1000689 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 p += xmlHeaderLen;
692 }
693 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300694 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 returnNode = new (_commentPool.Alloc()) XMLComment( this );
kezenatorec694152016-11-26 17:21:43 +1000696 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 p += commentHeaderLen;
699 }
700 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300701 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 p += cdataHeaderLen;
707 text->SetCData( true );
708 }
709 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300710 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
kezenatorec694152016-11-26 17:21:43 +1000712 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 p += dtdHeaderLen;
715 }
716 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300717 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 returnNode = new (_elementPool.Alloc()) XMLElement( this );
kezenatorec694152016-11-26 17:21:43 +1000719 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 p += elementHeaderLen;
722 }
723 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300724 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 returnNode = new (_textPool.Alloc()) XMLText( this );
726 returnNode->_memPool = &_textPool;
kezenatorec694152016-11-26 17:21:43 +1000727 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000729 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800731
Dmitry-Me02384662015-03-03 16:02:13 +0300732 TIXMLASSERT( returnNode );
733 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 *node = returnNode;
735 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800736}
737
738
Lee Thomason751da522012-02-10 08:50:51 -0800739bool XMLDocument::Accept( XMLVisitor* visitor ) const
740{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300741 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700742 if ( visitor->VisitEnter( *this ) ) {
743 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
744 if ( !node->Accept( visitor ) ) {
745 break;
746 }
747 }
748 }
749 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800750}
Lee Thomason56bdd022012-02-09 18:16:58 -0800751
752
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800753// --------- XMLNode ----------- //
754
755XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 _document( doc ),
757 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000758 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200760 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700761 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200762 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800763{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800764}
765
766
767XMLNode::~XMLNode()
768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 if ( _parent ) {
771 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800773}
774
Michael Daumling21626882013-10-22 17:03:37 +0200775const char* XMLNode::Value() const
776{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300777 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530778 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530779 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200780 return _value.GetStr();
781}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800782
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800783void XMLNode::SetValue( const char* str, bool staticMem )
784{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
788 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800791}
792
793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800794void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800795{
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300797 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300798 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800801}
802
803
804void XMLNode::Unlink( XMLNode* child )
805{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300806 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300807 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300808 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( child == _firstChild ) {
810 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( child == _lastChild ) {
813 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomasond923c672012-01-23 08:44:25 -0800815
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( child->_prev ) {
817 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 if ( child->_next ) {
820 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700822 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823}
824
825
U-Stream\Leeae25a442012-02-17 17:48:16 -0800826void XMLNode::DeleteChild( XMLNode* node )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100831 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400832 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800833}
834
835
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800836XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
837{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300838 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300839 if ( addThis->_document != _document ) {
840 TIXMLASSERT( false );
841 return 0;
842 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800843 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700844
Lee Thomason624d43f2012-10-12 10:58:48 -0700845 if ( _lastChild ) {
846 TIXMLASSERT( _firstChild );
847 TIXMLASSERT( _lastChild->_next == 0 );
848 _lastChild->_next = addThis;
849 addThis->_prev = _lastChild;
850 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _firstChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800863}
864
865
Lee Thomason1ff38e02012-02-14 18:18:16 -0800866XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
867{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300868 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800873 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700874
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 if ( _firstChild ) {
876 TIXMLASSERT( _lastChild );
877 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 _firstChild->_prev = addThis;
880 addThis->_next = _firstChild;
881 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 TIXMLASSERT( _lastChild == 0 );
887 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 addThis->_prev = 0;
890 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400893 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800894}
895
896
897XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
898{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300899 TIXMLASSERT( addThis );
900 if ( addThis->_document != _document ) {
901 TIXMLASSERT( false );
902 return 0;
903 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700904
Dmitry-Meabb2d042014-12-09 12:59:31 +0300905 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700906
Lee Thomason624d43f2012-10-12 10:58:48 -0700907 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300908 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 return 0;
910 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800911
Lee Thomason624d43f2012-10-12 10:58:48 -0700912 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 // The last node or the only node.
914 return InsertEndChild( addThis );
915 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800916 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 addThis->_prev = afterThis;
918 addThis->_next = afterThis->_next;
919 afterThis->_next->_prev = addThis;
920 afterThis->_next = addThis;
921 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800923}
924
925
926
927
Dmitry-Me886ad972015-07-22 11:00:51 +0300928const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800929{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300930 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300931 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300933 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 }
935 }
936 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800937}
938
939
Dmitry-Me886ad972015-07-22 11:00:51 +0300940const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800941{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300942 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300943 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300945 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 }
948 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800949}
950
951
Dmitry-Me886ad972015-07-22 11:00:51 +0300952const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800953{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300954 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300955 const XMLElement* element = node->ToElementWithName( name );
956 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400957 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 }
960 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961}
962
963
Dmitry-Me886ad972015-07-22 11:00:51 +0300964const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300966 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 const XMLElement* element = node->ToElementWithName( name );
968 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400969 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 }
972 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973}
974
975
kezenator4f756162016-11-29 19:46:27 +1000976char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800977{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 // This is a recursive method, but thinking about it "at the current level"
979 // it is a pretty simple flat list:
980 // <foo/>
981 // <!-- comment -->
982 //
983 // With a special case:
984 // <foo>
985 // </foo>
986 // <!-- comment -->
987 //
988 // Where the closing element (/foo) *must* be the next thing after the opening
989 // element, and the names must match. BUT the tricky bit is that the closing
990 // element will be read by the child.
991 //
992 // 'endTag' is the end tag for this node, it is returned by a call to a child.
993 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 while( p && *p ) {
996 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800997
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300999 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001000 if ( node == 0 ) {
1001 break;
1002 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001003
kezenatore3531812016-11-29 19:49:07 +10001004 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001007 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001009 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001010 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001011 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 }
1013 break;
1014 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001015
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301016 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301017 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001018 // Declarations are only allowed at document level
1019 bool wellLocated = ( ToDocument() != 0 );
1020 if ( wellLocated ) {
1021 // Multiple declarations are allowed but all declarations
1022 // must occur before anything else
1023 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1024 if ( !existingNode->ToDeclaration() ) {
1025 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301026 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001027 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301028 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001029 }
1030 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001031 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001032 DeleteNode( node );
1033 break;
1034 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301035 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301036
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001037 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001039 // We read the end tag. Return it to the parent.
1040 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1041 if ( parentEnd ) {
1042 ele->_value.TransferTo( parentEnd );
1043 }
1044 node->_memPool->SetTracked(); // created and then immediately deleted.
1045 DeleteNode( node );
1046 return p;
1047 }
1048
1049 // Handle an end tag returned to this level.
1050 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001051 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001052 if ( endTag.Empty() ) {
1053 if ( ele->ClosingType() == XMLElement::OPEN ) {
1054 mismatch = true;
1055 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001057 else {
1058 if ( ele->ClosingType() != XMLElement::OPEN ) {
1059 mismatch = true;
1060 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001061 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001062 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 }
1064 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001065 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001066 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001067 DeleteNode( node );
1068 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001069 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
JayXondbfdd8f2014-12-12 20:07:14 -05001071 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 }
1073 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001074}
1075
Dmitry-Mee3225b12014-09-03 11:03:11 +04001076void XMLNode::DeleteNode( XMLNode* node )
1077{
1078 if ( node == 0 ) {
1079 return;
1080 }
1081 MemPool* pool = node->_memPool;
1082 node->~XMLNode();
1083 pool->Free( node );
1084}
1085
Lee Thomason3cebdc42015-01-05 17:16:28 -08001086void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001087{
1088 TIXMLASSERT( insertThis );
1089 TIXMLASSERT( insertThis->_document == _document );
1090
1091 if ( insertThis->_parent )
1092 insertThis->_parent->Unlink( insertThis );
1093 else
1094 insertThis->_memPool->SetTracked();
1095}
1096
Dmitry-Meecb9b072016-10-12 16:44:59 +03001097const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1098{
1099 const XMLElement* element = this->ToElement();
1100 if ( element == 0 ) {
1101 return 0;
1102 }
1103 if ( name == 0 ) {
1104 return element;
1105 }
1106 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1107 return element;
1108 }
1109 return 0;
1110}
1111
Lee Thomason5492a1c2012-01-23 15:32:10 -08001112// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001113char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 const char* start = p;
1116 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001117 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001119 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 return p;
1122 }
1123 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001124 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1125 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001126 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001128
kezenator4f756162016-11-29 19:46:27 +10001129 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( p && *p ) {
1131 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001132 }
1133 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001134 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 }
1136 }
1137 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001138}
1139
1140
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001141XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001144 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 }
1146 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1147 text->SetCData( this->CData() );
1148 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001149}
1150
1151
1152bool XMLText::ShallowEqual( const XMLNode* compare ) const
1153{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001154 const XMLText* text = compare->ToText();
1155 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001156}
1157
1158
Lee Thomason56bdd022012-02-09 18:16:58 -08001159bool XMLText::Accept( XMLVisitor* visitor ) const
1160{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001161 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001163}
1164
1165
Lee Thomason3f57d272012-01-11 15:30:03 -08001166// --------- XMLComment ---------- //
1167
Lee Thomasone4422302012-01-20 17:59:50 -08001168XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001169{
1170}
1171
1172
Lee Thomasonce0763e2012-01-11 15:43:54 -08001173XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001174{
Lee Thomason3f57d272012-01-11 15:30:03 -08001175}
1176
1177
kezenator4f756162016-11-29 19:46:27 +10001178char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 // Comment parses as text.
1181 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001182 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001184 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 }
1186 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001187}
1188
1189
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001190XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001193 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 }
1195 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1196 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001197}
1198
1199
1200bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1201{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001202 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001203 const XMLComment* comment = compare->ToComment();
1204 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001205}
1206
1207
Lee Thomason751da522012-02-10 08:50:51 -08001208bool XMLComment::Accept( XMLVisitor* visitor ) const
1209{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001210 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001212}
Lee Thomason56bdd022012-02-09 18:16:58 -08001213
1214
Lee Thomason50f97b22012-02-11 16:33:40 -08001215// --------- XMLDeclaration ---------- //
1216
1217XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1218{
1219}
1220
1221
1222XMLDeclaration::~XMLDeclaration()
1223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001225}
1226
1227
kezenator4f756162016-11-29 19:46:27 +10001228char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 // Declaration parses as text.
1231 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001232 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001234 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 }
1236 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001237}
1238
1239
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001240XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 }
1245 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1246 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001247}
1248
1249
1250bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1251{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001252 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001253 const XMLDeclaration* declaration = compare->ToDeclaration();
1254 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001255}
1256
1257
1258
Lee Thomason50f97b22012-02-11 16:33:40 -08001259bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1260{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001261 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001263}
1264
1265// --------- XMLUnknown ---------- //
1266
1267XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1268{
1269}
1270
1271
1272XMLUnknown::~XMLUnknown()
1273{
1274}
1275
1276
kezenator4f756162016-11-29 19:46:27 +10001277char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 // Unknown parses as text.
1280 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001281
kezenator4f756162016-11-29 19:46:27 +10001282 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001284 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 }
1286 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001287}
1288
1289
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001290XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001293 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 }
1295 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1296 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001297}
1298
1299
1300bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1301{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001302 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001303 const XMLUnknown* unknown = compare->ToUnknown();
1304 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001305}
1306
1307
Lee Thomason50f97b22012-02-11 16:33:40 -08001308bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1309{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001310 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001312}
1313
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001314// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001315
1316const char* XMLAttribute::Name() const
1317{
1318 return _name.GetStr();
1319}
1320
1321const char* XMLAttribute::Value() const
1322{
1323 return _value.GetStr();
1324}
1325
kezenator4f756162016-11-29 19:46:27 +10001326char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001329 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 if ( !p || !*p ) {
1331 return 0;
1332 }
Lee Thomason22aead12012-01-23 13:29:35 -08001333
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001335 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001336 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 return 0;
1338 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001339
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001341 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( *p != '\"' && *p != '\'' ) {
1343 return 0;
1344 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001345
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 char endTag[2] = { *p, 0 };
1347 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001348
kezenator4f756162016-11-29 19:46:27 +10001349 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351}
1352
1353
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001354void XMLAttribute::SetName( const char* n )
1355{
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001357}
1358
1359
Lee Thomason2fa81722012-11-09 12:37:46 -08001360XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001363 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 }
1365 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001366}
1367
1368
Lee Thomason2fa81722012-11-09 12:37:46 -08001369XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( XMLUtil::ToUnsigned( 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 Thomason51c12712016-06-04 20:18:49 -07001378XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1379{
1380 if (XMLUtil::ToInt64(Value(), value)) {
1381 return XML_SUCCESS;
1382 }
1383 return XML_WRONG_ATTRIBUTE_TYPE;
1384}
1385
1386
Lee Thomason2fa81722012-11-09 12:37:46 -08001387XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::ToBool( 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
Lee Thomason2fa81722012-11-09 12:37:46 -08001396XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001399 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 }
1401 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001402}
1403
1404
Lee Thomason2fa81722012-11-09 12:37:46 -08001405XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001408 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 }
1410 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001411}
1412
1413
1414void XMLAttribute::SetAttribute( const char* v )
1415{
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001417}
1418
1419
Lee Thomason1ff38e02012-02-14 18:18:16 -08001420void XMLAttribute::SetAttribute( int v )
1421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 char buf[BUF_SIZE];
1423 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001425}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001426
1427
1428void XMLAttribute::SetAttribute( unsigned v )
1429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 char buf[BUF_SIZE];
1431 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001433}
1434
1435
Lee Thomason51c12712016-06-04 20:18:49 -07001436void XMLAttribute::SetAttribute(int64_t v)
1437{
1438 char buf[BUF_SIZE];
1439 XMLUtil::ToStr(v, buf, BUF_SIZE);
1440 _value.SetStr(buf);
1441}
1442
1443
1444
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001445void XMLAttribute::SetAttribute( bool v )
1446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 char buf[BUF_SIZE];
1448 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001450}
1451
1452void XMLAttribute::SetAttribute( double v )
1453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 char buf[BUF_SIZE];
1455 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001457}
1458
1459void XMLAttribute::SetAttribute( float v )
1460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 char buf[BUF_SIZE];
1462 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001464}
1465
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001466
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467// --------- XMLElement ---------- //
1468XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _closingType( 0 ),
1470 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001471{
1472}
1473
1474
1475XMLElement::~XMLElement()
1476{
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 while( _rootAttribute ) {
1478 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001479 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001482}
1483
1484
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001485const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1486{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001487 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1489 return a;
1490 }
1491 }
1492 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001493}
1494
1495
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001496const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 const XMLAttribute* a = FindAttribute( name );
1499 if ( !a ) {
1500 return 0;
1501 }
1502 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1503 return a->Value();
1504 }
1505 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001506}
1507
Josh Wittnercf3dd092016-10-11 18:57:17 -07001508int XMLElement::IntAttribute(const char* name, int defaultValue) const
1509{
1510 int i = defaultValue;
1511 QueryIntAttribute(name, &i);
1512 return i;
1513}
1514
1515unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1516{
1517 unsigned i = defaultValue;
1518 QueryUnsignedAttribute(name, &i);
1519 return i;
1520}
1521
1522int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1523{
1524 int64_t i = defaultValue;
1525 QueryInt64Attribute(name, &i);
1526 return i;
1527}
1528
1529bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1530{
1531 bool b = defaultValue;
1532 QueryBoolAttribute(name, &b);
1533 return b;
1534}
1535
1536double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1537{
1538 double d = defaultValue;
1539 QueryDoubleAttribute(name, &d);
1540 return d;
1541}
1542
1543float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1544{
1545 float f = defaultValue;
1546 QueryFloatAttribute(name, &f);
1547 return f;
1548}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001549
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001550const char* XMLElement::GetText() const
1551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001553 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 }
1555 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001556}
1557
1558
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001559void XMLElement::SetText( const char* inText )
1560{
Uli Kusterer869bb592014-01-21 01:36:16 +01001561 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001562 FirstChild()->SetValue( inText );
1563 else {
1564 XMLText* theText = GetDocument()->NewText( inText );
1565 InsertFirstChild( theText );
1566 }
1567}
1568
Lee Thomason5bb2d802014-01-24 10:42:57 -08001569
1570void XMLElement::SetText( int v )
1571{
1572 char buf[BUF_SIZE];
1573 XMLUtil::ToStr( v, buf, BUF_SIZE );
1574 SetText( buf );
1575}
1576
1577
1578void XMLElement::SetText( unsigned v )
1579{
1580 char buf[BUF_SIZE];
1581 XMLUtil::ToStr( v, buf, BUF_SIZE );
1582 SetText( buf );
1583}
1584
1585
Lee Thomason51c12712016-06-04 20:18:49 -07001586void XMLElement::SetText(int64_t v)
1587{
1588 char buf[BUF_SIZE];
1589 XMLUtil::ToStr(v, buf, BUF_SIZE);
1590 SetText(buf);
1591}
1592
1593
1594void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001595{
1596 char buf[BUF_SIZE];
1597 XMLUtil::ToStr( v, buf, BUF_SIZE );
1598 SetText( buf );
1599}
1600
1601
1602void XMLElement::SetText( float v )
1603{
1604 char buf[BUF_SIZE];
1605 XMLUtil::ToStr( v, buf, BUF_SIZE );
1606 SetText( buf );
1607}
1608
1609
1610void XMLElement::SetText( double v )
1611{
1612 char buf[BUF_SIZE];
1613 XMLUtil::ToStr( v, buf, BUF_SIZE );
1614 SetText( buf );
1615}
1616
1617
MortenMacFly4ee49f12013-01-14 20:03:14 +01001618XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001621 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001622 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 return XML_SUCCESS;
1624 }
1625 return XML_CAN_NOT_CONVERT_TEXT;
1626 }
1627 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001628}
1629
1630
MortenMacFly4ee49f12013-01-14 20:03:14 +01001631XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001634 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001635 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 return XML_SUCCESS;
1637 }
1638 return XML_CAN_NOT_CONVERT_TEXT;
1639 }
1640 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001641}
1642
1643
Lee Thomason51c12712016-06-04 20:18:49 -07001644XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1645{
1646 if (FirstChild() && FirstChild()->ToText()) {
1647 const char* t = FirstChild()->Value();
1648 if (XMLUtil::ToInt64(t, ival)) {
1649 return XML_SUCCESS;
1650 }
1651 return XML_CAN_NOT_CONVERT_TEXT;
1652 }
1653 return XML_NO_TEXT_NODE;
1654}
1655
1656
MortenMacFly4ee49f12013-01-14 20:03:14 +01001657XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001658{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001660 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001661 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 return XML_SUCCESS;
1663 }
1664 return XML_CAN_NOT_CONVERT_TEXT;
1665 }
1666 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001667}
1668
1669
MortenMacFly4ee49f12013-01-14 20:03:14 +01001670XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001671{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001673 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001674 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001675 return XML_SUCCESS;
1676 }
1677 return XML_CAN_NOT_CONVERT_TEXT;
1678 }
1679 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001680}
1681
1682
MortenMacFly4ee49f12013-01-14 20:03:14 +01001683XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001684{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001686 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001687 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 return XML_SUCCESS;
1689 }
1690 return XML_CAN_NOT_CONVERT_TEXT;
1691 }
1692 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001693}
1694
Josh Wittnercf3dd092016-10-11 18:57:17 -07001695int XMLElement::IntText(int defaultValue) const
1696{
1697 int i = defaultValue;
1698 QueryIntText(&i);
1699 return i;
1700}
1701
1702unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1703{
1704 unsigned i = defaultValue;
1705 QueryUnsignedText(&i);
1706 return i;
1707}
1708
1709int64_t XMLElement::Int64Text(int64_t defaultValue) const
1710{
1711 int64_t i = defaultValue;
1712 QueryInt64Text(&i);
1713 return i;
1714}
1715
1716bool XMLElement::BoolText(bool defaultValue) const
1717{
1718 bool b = defaultValue;
1719 QueryBoolText(&b);
1720 return b;
1721}
1722
1723double XMLElement::DoubleText(double defaultValue) const
1724{
1725 double d = defaultValue;
1726 QueryDoubleText(&d);
1727 return d;
1728}
1729
1730float XMLElement::FloatText(float defaultValue) const
1731{
1732 float f = defaultValue;
1733 QueryFloatText(&f);
1734 return f;
1735}
Lee Thomason21be8822012-07-15 17:27:22 -07001736
1737
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001738XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1739{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 XMLAttribute* last = 0;
1741 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1746 break;
1747 }
1748 }
1749 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001750 attrib = CreateAttribute();
1751 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001753 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 }
1756 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001757 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 }
1760 attrib->SetName( name );
1761 }
1762 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001763}
1764
1765
U-Stream\Leeae25a442012-02-17 17:48:16 -08001766void XMLElement::DeleteAttribute( const char* name )
1767{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1771 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 }
1774 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001777 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 break;
1779 }
1780 prev = a;
1781 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001782}
1783
1784
kezenator4f756162016-11-29 19:46:27 +10001785char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001786{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 const char* start = p;
1788 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001789
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 // Read the attributes.
1791 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001792 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001793 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001794 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 return 0;
1796 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001797
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001799 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001800 XMLAttribute* attrib = CreateAttribute();
1801 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001802 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001803
kezenatorec694152016-11-26 17:21:43 +10001804 int attrLineNum = attrib->_parseLineNum;
1805
kezenator4f756162016-11-29 19:46:27 +10001806 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001808 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001809 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 return 0;
1811 }
1812 // There is a minor bug here: if the attribute in the source xml
1813 // document is duplicated, it will not be detected and the
1814 // attribute will be doubly added. However, tracking the 'prevAttribute'
1815 // avoids re-scanning the attribute list. Preferring performance for
1816 // now, may reconsider in the future.
1817 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001818 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
1821 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001822 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
1825 prevAttribute = attrib;
1826 }
1827 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 else if ( *p == '>' ) {
1829 ++p;
1830 break;
1831 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001832 // end of the tag
1833 else if ( *p == '/' && *(p+1) == '>' ) {
1834 _closingType = CLOSED;
1835 return p+2; // done; sealed element.
1836 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 else {
kezenatorec694152016-11-26 17:21:43 +10001838 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 return 0;
1840 }
1841 }
1842 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001843}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001844
Dmitry-Mee3225b12014-09-03 11:03:11 +04001845void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1846{
1847 if ( attribute == 0 ) {
1848 return;
1849 }
1850 MemPool* pool = attribute->_memPool;
1851 attribute->~XMLAttribute();
1852 pool->Free( attribute );
1853}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001854
Dmitry-Mea60caa22016-11-22 18:28:08 +03001855XMLAttribute* XMLElement::CreateAttribute()
1856{
1857 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1858 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1859 attrib->_memPool = &_document->_attributePool;
1860 attrib->_memPool->SetTracked();
1861 return attrib;
1862}
1863
Lee Thomason67d61312012-01-24 16:01:51 -08001864//
1865// <ele></ele>
1866// <ele>foo<b>bar</b></ele>
1867//
kezenator4f756162016-11-29 19:46:27 +10001868char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001869{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001871 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001872
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 // The closing element is the </element> form. It is
1874 // parsed just like a regular element then deleted from
1875 // the DOM.
1876 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001877 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 ++p;
1879 }
Lee Thomason67d61312012-01-24 16:01:51 -08001880
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 p = _value.ParseName( p );
1882 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 return 0;
1884 }
Lee Thomason67d61312012-01-24 16:01:51 -08001885
kezenator4f756162016-11-29 19:46:27 +10001886 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 return p;
1889 }
Lee Thomason67d61312012-01-24 16:01:51 -08001890
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001893}
1894
1895
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001896
1897XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 }
1902 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1903 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1904 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1905 }
1906 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001907}
1908
1909
1910bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1911{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001912 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001914 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001915
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 const XMLAttribute* a=FirstAttribute();
1917 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 while ( a && b ) {
1920 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1921 return false;
1922 }
1923 a = a->Next();
1924 b = b->Next();
1925 }
1926 if ( a || b ) {
1927 // different count
1928 return false;
1929 }
1930 return true;
1931 }
1932 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001933}
1934
1935
Lee Thomason751da522012-02-10 08:50:51 -08001936bool XMLElement::Accept( XMLVisitor* visitor ) const
1937{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001938 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1941 if ( !node->Accept( visitor ) ) {
1942 break;
1943 }
1944 }
1945 }
1946 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001947}
Lee Thomason56bdd022012-02-09 18:16:58 -08001948
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001949
Lee Thomason3f57d272012-01-11 15:30:03 -08001950// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001951
1952// Warning: List must match 'enum XMLError'
1953const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1954 "XML_SUCCESS",
1955 "XML_NO_ATTRIBUTE",
1956 "XML_WRONG_ATTRIBUTE_TYPE",
1957 "XML_ERROR_FILE_NOT_FOUND",
1958 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1959 "XML_ERROR_FILE_READ_ERROR",
1960 "XML_ERROR_ELEMENT_MISMATCH",
1961 "XML_ERROR_PARSING_ELEMENT",
1962 "XML_ERROR_PARSING_ATTRIBUTE",
1963 "XML_ERROR_IDENTIFYING_TAG",
1964 "XML_ERROR_PARSING_TEXT",
1965 "XML_ERROR_PARSING_CDATA",
1966 "XML_ERROR_PARSING_COMMENT",
1967 "XML_ERROR_PARSING_DECLARATION",
1968 "XML_ERROR_PARSING_UNKNOWN",
1969 "XML_ERROR_EMPTY_DOCUMENT",
1970 "XML_ERROR_MISMATCHED_ELEMENT",
1971 "XML_ERROR_PARSING",
1972 "XML_CAN_NOT_CONVERT_TEXT",
1973 "XML_NO_TEXT_NODE"
1974};
1975
1976
Lee Thomason624d43f2012-10-12 10:58:48 -07001977XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 _writeBOM( false ),
1980 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001981 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001982 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001983 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001984{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001985 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1986 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001987}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001988
1989
Lee Thomason3f57d272012-01-11 15:30:03 -08001990XMLDocument::~XMLDocument()
1991{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001992 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001993}
1994
1995
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001996void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001997{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001998 DeleteChildren();
1999
Dmitry-Meab37df82014-11-28 12:08:36 +03002000#ifdef DEBUG
2001 const bool hadError = Error();
2002#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002003 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002004
Lee Thomason624d43f2012-10-12 10:58:48 -07002005 delete [] _charBuffer;
2006 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002007
2008#if 0
2009 _textPool.Trace( "text" );
2010 _elementPool.Trace( "element" );
2011 _commentPool.Trace( "comment" );
2012 _attributePool.Trace( "attribute" );
2013#endif
2014
2015#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002016 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002017 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2018 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2019 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2020 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2021 }
2022#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002023}
2024
Lee Thomason3f57d272012-01-11 15:30:03 -08002025
Lee Thomason2c85a712012-01-31 08:24:24 -08002026XMLElement* XMLDocument::NewElement( const char* name )
2027{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002028 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
2030 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 ele->SetName( name );
2032 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002033}
2034
2035
Lee Thomason1ff38e02012-02-14 18:18:16 -08002036XMLComment* XMLDocument::NewComment( const char* str )
2037{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002038 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
2040 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 comment->SetValue( str );
2042 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002043}
2044
2045
2046XMLText* XMLDocument::NewText( const char* str )
2047{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002048 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 XMLText* text = new (_textPool.Alloc()) XMLText( this );
2050 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 text->SetValue( str );
2052 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002053}
2054
2055
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002056XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2057{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002058 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2060 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2062 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002063}
2064
2065
2066XMLUnknown* XMLDocument::NewUnknown( const char* str )
2067{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002068 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2070 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 unk->SetValue( str );
2072 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002073}
2074
Dmitry-Me01578db2014-08-19 10:18:48 +04002075static FILE* callfopen( const char* filepath, const char* mode )
2076{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002077 TIXMLASSERT( filepath );
2078 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002079#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2080 FILE* fp = 0;
2081 errno_t err = fopen_s( &fp, filepath, mode );
2082 if ( err ) {
2083 return 0;
2084 }
2085#else
2086 FILE* fp = fopen( filepath, mode );
2087#endif
2088 return fp;
2089}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002090
2091void XMLDocument::DeleteNode( XMLNode* node ) {
2092 TIXMLASSERT( node );
2093 TIXMLASSERT(node->_document == this );
2094 if (node->_parent) {
2095 node->_parent->DeleteChild( node );
2096 }
2097 else {
2098 // Isn't in the tree.
2099 // Use the parent delete.
2100 // Also, we need to mark it tracked: we 'know'
2101 // it was never used.
2102 node->_memPool->SetTracked();
2103 // Call the static XMLNode version:
2104 XMLNode::DeleteNode(node);
2105 }
2106}
2107
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108
Lee Thomason2fa81722012-11-09 12:37:46 -08002109XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002110{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002111 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002112 FILE* fp = callfopen( filename, "rb" );
2113 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002114 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002115 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 }
2117 LoadFile( fp );
2118 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002120}
2121
Dmitry-Me901fed52015-09-25 10:29:51 +03002122// This is likely overengineered template art to have a check that unsigned long value incremented
2123// by one still fits into size_t. If size_t type is larger than unsigned long type
2124// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2125// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2126// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2127// types sizes relate to each other.
2128template
2129<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2130struct LongFitsIntoSizeTMinusOne {
2131 static bool Fits( unsigned long value )
2132 {
2133 return value < (size_t)-1;
2134 }
2135};
2136
2137template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002138struct LongFitsIntoSizeTMinusOne<false> {
2139 static bool Fits( unsigned long )
2140 {
2141 return true;
2142 }
2143};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002144
Lee Thomason2fa81722012-11-09 12:37:46 -08002145XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002147 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002148
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002149 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002150 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002151 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002152 return _errorID;
2153 }
2154
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002156 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002158 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002159 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002160 return _errorID;
2161 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002162 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002163
Dmitry-Me901fed52015-09-25 10:29:51 +03002164 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002165 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002166 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002167 return _errorID;
2168 }
2169
Dmitry-Me72801b82015-05-07 09:41:39 +03002170 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002171 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002174
Dmitry-Me72801b82015-05-07 09:41:39 +03002175 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002176 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 _charBuffer = new char[size+1];
2178 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002180 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002183
Lee Thomason624d43f2012-10-12 10:58:48 -07002184 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002185
Dmitry-Me97476b72015-01-01 16:15:57 +03002186 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188}
2189
2190
Lee Thomason2fa81722012-11-09 12:37:46 -08002191XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002192{
Dmitry-Me01578db2014-08-19 10:18:48 +04002193 FILE* fp = callfopen( filename, "w" );
2194 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002195 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002196 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 }
2198 SaveFile(fp, compact);
2199 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002201}
2202
2203
Lee Thomason2fa81722012-11-09 12:37:46 -08002204XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002205{
Ant Mitchell189198f2015-03-24 16:20:36 +00002206 // Clear any error from the last save, otherwise it will get reported
2207 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002208 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 XMLPrinter stream( fp, compact );
2210 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002212}
2213
Lee Thomason1ff38e02012-02-14 18:18:16 -08002214
Lee Thomason2fa81722012-11-09 12:37:46 -08002215XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002216{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002217 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002218
Lee Thomason82d32002014-02-21 22:47:18 -08002219 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002220 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
2223 if ( len == (size_t)(-1) ) {
2224 len = strlen( p );
2225 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002226 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _charBuffer = new char[ len+1 ];
2228 memcpy( _charBuffer, p, len );
2229 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002230
Dmitry-Me97476b72015-01-01 16:15:57 +03002231 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002232 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002233 // clean up now essentially dangling memory.
2234 // and the parse fail can put objects in the
2235 // pools that are dead and inaccessible.
2236 DeleteChildren();
2237 _elementPool.Clear();
2238 _attributePool.Clear();
2239 _textPool.Clear();
2240 _commentPool.Clear();
2241 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002243}
2244
2245
PKEuS1c5f99e2013-07-06 11:28:39 +02002246void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002247{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002248 if ( streamer ) {
2249 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002251 else {
2252 XMLPrinter stdoutStreamer( stdout );
2253 Accept( &stdoutStreamer );
2254 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002255}
2256
2257
kezenatorec694152016-11-26 17:21:43 +10002258void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002259{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002260 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002262
2263 _errorStr1.Reset();
2264 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002265 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002266
2267 if (str1)
2268 _errorStr1.SetStr(str1);
2269 if (str2)
2270 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002271}
2272
Lee Thomasone90e9012016-12-24 07:34:39 -08002273/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002274{
kezenator5a700712016-11-26 13:54:42 +10002275 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2276 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002277 TIXMLASSERT( errorName && errorName[0] );
2278 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002279}
Lee Thomason5cae8972012-01-24 18:03:07 -08002280
kezenator5a700712016-11-26 13:54:42 +10002281const char* XMLDocument::ErrorName() const
2282{
Lee Thomasone90e9012016-12-24 07:34:39 -08002283 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002284}
2285
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002286void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002287{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002288 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 static const int LEN = 20;
2290 char buf1[LEN] = { 0 };
2291 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002292
Lee Thomason584af572016-09-05 14:14:16 -07002293 if ( !_errorStr1.Empty() ) {
2294 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 }
Lee Thomason584af572016-09-05 14:14:16 -07002296 if ( !_errorStr2.Empty() ) {
2297 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299
Dmitry-Me2ad43202015-04-16 12:18:58 +03002300 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2301 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2302 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002303 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2304 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306}
2307
Dmitry-Me97476b72015-01-01 16:15:57 +03002308void XMLDocument::Parse()
2309{
2310 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2311 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002312 _parseCurLineNum = 1;
2313 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002314 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002315 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002316 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002317 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002318 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002319 return;
2320 }
kezenator4f756162016-11-29 19:46:27 +10002321 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002322}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002323
PKEuS1bfb9542013-08-04 13:51:17 +02002324XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002325 _elementJustOpened( false ),
2326 _firstElement( true ),
2327 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002328 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002329 _textDepth( -1 ),
2330 _processEntities( true ),
2331 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002334 _entityFlag[i] = false;
2335 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 }
2337 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002338 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002339 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002340 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002342 _restrictedEntityFlag[(unsigned char)'&'] = true;
2343 _restrictedEntityFlag[(unsigned char)'<'] = true;
2344 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002345 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002346}
2347
2348
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002349void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002350{
2351 va_list va;
2352 va_start( va, format );
2353
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 if ( _fp ) {
2355 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 }
2357 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002358 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 // Close out and re-start the va-args
2360 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002361 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002363 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002364 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002365 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002366 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002367 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002368}
2369
2370
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002371void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 for( int i=0; i<depth; ++i ) {
2374 Print( " " );
2375 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002376}
2377
2378
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002379void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002381 // Look for runs of bytes between entities to print.
2382 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002383
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002385 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002387 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 // Remember, char is sometimes signed. (How many times has that bitten me?)
2389 if ( *q > 0 && *q < ENTITY_RANGE ) {
2390 // Check for entities. If one is found, flush
2391 // the stream up until the entity, write the
2392 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002393 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002395 const size_t delta = q - p;
2396 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002397 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002398 Print( "%.*s", toPrint, p );
2399 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002401 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002402 for( int i=0; i<NUM_ENTITIES; ++i ) {
2403 if ( entities[i].value == *q ) {
2404 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002405 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 break;
2407 }
2408 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002409 if ( !entityPatternPrinted ) {
2410 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2411 TIXMLASSERT( false );
2412 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002413 ++p;
2414 }
2415 }
2416 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002417 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
2419 }
2420 // Flush the remaining string. This will be the entire
2421 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002422 TIXMLASSERT( p <= q );
2423 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 Print( "%s", p );
2425 }
Lee Thomason857b8682012-01-25 17:50:25 -08002426}
2427
U-Stream\Leeae25a442012-02-17 17:48:16 -08002428
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002429void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002432 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 -07002433 Print( "%s", bom );
2434 }
2435 if ( writeDec ) {
2436 PushDeclaration( "xml version=\"1.0\"" );
2437 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002438}
2439
2440
Uli Kusterer593a33d2014-02-01 12:48:51 +01002441void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002442{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002443 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002444 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002445
Uli Kusterer593a33d2014-02-01 12:48:51 +01002446 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002448 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002449 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002450 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002452
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002454 _elementJustOpened = true;
2455 _firstElement = false;
2456 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002457}
2458
2459
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002460void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002461{
Lee Thomason624d43f2012-10-12 10:58:48 -07002462 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002463 Print( " %s=\"", name );
2464 PrintString( value, false );
2465 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002466}
2467
2468
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002469void XMLPrinter::PushAttribute( const char* name, int v )
2470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002471 char buf[BUF_SIZE];
2472 XMLUtil::ToStr( v, buf, BUF_SIZE );
2473 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002474}
2475
2476
2477void XMLPrinter::PushAttribute( const char* name, unsigned v )
2478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 char buf[BUF_SIZE];
2480 XMLUtil::ToStr( v, buf, BUF_SIZE );
2481 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002482}
2483
2484
Lee Thomason51c12712016-06-04 20:18:49 -07002485void XMLPrinter::PushAttribute(const char* name, int64_t v)
2486{
2487 char buf[BUF_SIZE];
2488 XMLUtil::ToStr(v, buf, BUF_SIZE);
2489 PushAttribute(name, buf);
2490}
2491
2492
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002493void XMLPrinter::PushAttribute( const char* name, bool v )
2494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 char buf[BUF_SIZE];
2496 XMLUtil::ToStr( v, buf, BUF_SIZE );
2497 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002498}
2499
2500
2501void XMLPrinter::PushAttribute( const char* name, double v )
2502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 char buf[BUF_SIZE];
2504 XMLUtil::ToStr( v, buf, BUF_SIZE );
2505 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002506}
2507
2508
Uli Kustererca412e82014-02-01 13:35:05 +01002509void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002510{
Lee Thomason624d43f2012-10-12 10:58:48 -07002511 --_depth;
2512 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002513
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 Print( "/>" );
2516 }
2517 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002518 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002519 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002520 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 }
2522 Print( "</%s>", name );
2523 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002524
Lee Thomason624d43f2012-10-12 10:58:48 -07002525 if ( _textDepth == _depth ) {
2526 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 }
Uli Kustererca412e82014-02-01 13:35:05 +01002528 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002529 Print( "\n" );
2530 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002531 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002532}
2533
2534
Dmitry-Mea092bc12014-12-23 17:57:05 +03002535void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002536{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002537 if ( !_elementJustOpened ) {
2538 return;
2539 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002540 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002542}
2543
2544
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002545void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002546{
Lee Thomason624d43f2012-10-12 10:58:48 -07002547 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002548
Dmitry-Mea092bc12014-12-23 17:57:05 +03002549 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002550 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002551 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002552 }
2553 else {
2554 PrintString( text, true );
2555 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002556}
2557
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002558void XMLPrinter::PushText( int64_t value )
2559{
2560 char buf[BUF_SIZE];
2561 XMLUtil::ToStr( value, buf, BUF_SIZE );
2562 PushText( buf, false );
2563}
2564
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002565void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002567 char buf[BUF_SIZE];
2568 XMLUtil::ToStr( value, buf, BUF_SIZE );
2569 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002570}
2571
2572
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002573void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002575 char buf[BUF_SIZE];
2576 XMLUtil::ToStr( value, buf, BUF_SIZE );
2577 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002578}
2579
2580
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002581void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002582{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002583 char buf[BUF_SIZE];
2584 XMLUtil::ToStr( value, buf, BUF_SIZE );
2585 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002586}
2587
2588
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002589void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002591 char buf[BUF_SIZE];
2592 XMLUtil::ToStr( value, buf, BUF_SIZE );
2593 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002594}
2595
2596
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002597void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002599 char buf[BUF_SIZE];
2600 XMLUtil::ToStr( value, buf, BUF_SIZE );
2601 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002602}
2603
Lee Thomason5cae8972012-01-24 18:03:07 -08002604
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002605void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002606{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002607 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002608 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002610 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002612 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002614}
Lee Thomason751da522012-02-10 08:50:51 -08002615
2616
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002617void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002618{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002619 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002620 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002621 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002622 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002623 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002624 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002625 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002626}
2627
2628
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002629void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002630{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002631 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002632 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002633 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002634 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002635 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002636 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002637 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002638}
2639
2640
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002641bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002642{
Lee Thomason624d43f2012-10-12 10:58:48 -07002643 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 if ( doc.HasBOM() ) {
2645 PushHeader( true, false );
2646 }
2647 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002648}
2649
2650
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002651bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002652{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002653 const XMLElement* parentElem = 0;
2654 if ( element.Parent() ) {
2655 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002656 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002657 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002658 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002659 while ( attribute ) {
2660 PushAttribute( attribute->Name(), attribute->Value() );
2661 attribute = attribute->Next();
2662 }
2663 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002664}
2665
2666
Uli Kustererca412e82014-02-01 13:35:05 +01002667bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002668{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002669 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002670 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002671}
2672
2673
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002674bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002675{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 PushText( text.Value(), text.CData() );
2677 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002678}
2679
2680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002681bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002682{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002683 PushComment( comment.Value() );
2684 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002685}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002686
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002687bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002688{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 PushDeclaration( declaration.Value() );
2690 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002691}
2692
2693
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002694bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002695{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 PushUnknown( unknown.Value() );
2697 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002698}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002699
Lee Thomason685b8952012-11-12 13:00:06 -08002700} // namespace tinyxml2
2701