blob: 1f7a91846e78a17216666f58893f26d1662cafc4 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300681 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
kezenatorec694152016-11-26 17:21:43 +1000683 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 p += xmlHeaderLen;
686 }
687 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300688 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 returnNode = new (_commentPool.Alloc()) XMLComment( this );
kezenatorec694152016-11-26 17:21:43 +1000690 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 p += commentHeaderLen;
693 }
694 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300695 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000698 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += cdataHeaderLen;
701 text->SetCData( true );
702 }
703 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300704 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
kezenatorec694152016-11-26 17:21:43 +1000706 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 p += dtdHeaderLen;
709 }
710 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300711 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700712 returnNode = new (_elementPool.Alloc()) XMLElement( this );
kezenatorec694152016-11-26 17:21:43 +1000713 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p += elementHeaderLen;
716 }
717 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300718 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 returnNode = new (_textPool.Alloc()) XMLText( this );
720 returnNode->_memPool = &_textPool;
kezenatorec694152016-11-26 17:21:43 +1000721 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000723 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800725
Dmitry-Me02384662015-03-03 16:02:13 +0300726 TIXMLASSERT( returnNode );
727 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 *node = returnNode;
729 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800730}
731
732
Lee Thomason751da522012-02-10 08:50:51 -0800733bool XMLDocument::Accept( XMLVisitor* visitor ) const
734{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300735 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 if ( visitor->VisitEnter( *this ) ) {
737 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
738 if ( !node->Accept( visitor ) ) {
739 break;
740 }
741 }
742 }
743 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800744}
Lee Thomason56bdd022012-02-09 18:16:58 -0800745
746
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800747// --------- XMLNode ----------- //
748
749XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 _document( doc ),
751 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000752 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200754 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700755 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200756 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800757{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800758}
759
760
761XMLNode::~XMLNode()
762{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 if ( _parent ) {
765 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800767}
768
Michael Daumling21626882013-10-22 17:03:37 +0200769const char* XMLNode::Value() const
770{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300771 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530772 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530773 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200774 return _value.GetStr();
775}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800776
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800777void XMLNode::SetValue( const char* str, bool staticMem )
778{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
782 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800785}
786
787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800789{
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300791 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300792 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800795}
796
797
798void XMLNode::Unlink( XMLNode* child )
799{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300800 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300801 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300802 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 if ( child == _firstChild ) {
804 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 if ( child == _lastChild ) {
807 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
Lee Thomasond923c672012-01-23 08:44:25 -0800809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( child->_prev ) {
811 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700813 if ( child->_next ) {
814 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700816 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800817}
818
819
U-Stream\Leeae25a442012-02-17 17:48:16 -0800820void XMLNode::DeleteChild( XMLNode* node )
821{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300822 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300823 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100825 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400826 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827}
828
829
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800830XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
831{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300832 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300833 if ( addThis->_document != _document ) {
834 TIXMLASSERT( false );
835 return 0;
836 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800837 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 if ( _lastChild ) {
840 TIXMLASSERT( _firstChild );
841 TIXMLASSERT( _lastChild->_next == 0 );
842 _lastChild->_next = addThis;
843 addThis->_prev = _lastChild;
844 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800845
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 }
848 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 TIXMLASSERT( _firstChild == 0 );
850 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
853 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800857}
858
859
Lee Thomason1ff38e02012-02-14 18:18:16 -0800860XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
861{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300862 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300863 if ( addThis->_document != _document ) {
864 TIXMLASSERT( false );
865 return 0;
866 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800867 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700868
Lee Thomason624d43f2012-10-12 10:58:48 -0700869 if ( _firstChild ) {
870 TIXMLASSERT( _lastChild );
871 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800872
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 _firstChild->_prev = addThis;
874 addThis->_next = _firstChild;
875 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 }
879 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 TIXMLASSERT( _lastChild == 0 );
881 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 addThis->_prev = 0;
884 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400887 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800888}
889
890
891XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
892{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300893 TIXMLASSERT( addThis );
894 if ( addThis->_document != _document ) {
895 TIXMLASSERT( false );
896 return 0;
897 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700898
Dmitry-Meabb2d042014-12-09 12:59:31 +0300899 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700900
Lee Thomason624d43f2012-10-12 10:58:48 -0700901 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300902 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 return 0;
904 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 // The last node or the only node.
908 return InsertEndChild( addThis );
909 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800910 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 addThis->_prev = afterThis;
912 addThis->_next = afterThis->_next;
913 afterThis->_next->_prev = addThis;
914 afterThis->_next = addThis;
915 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800917}
918
919
920
921
Dmitry-Me886ad972015-07-22 11:00:51 +0300922const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800923{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300924 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300925 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300937 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300939 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800943}
944
945
Dmitry-Me886ad972015-07-22 11:00:51 +0300946const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300948 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300949 const XMLElement* element = node->ToElementWithName( name );
950 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400951 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 }
954 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
Dmitry-Me886ad972015-07-22 11:00:51 +0300958const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300960 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300961 const XMLElement* element = node->ToElementWithName( name );
962 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400963 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 }
965 }
966 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800967}
968
969
kezenator4f756162016-11-29 19:46:27 +1000970char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800971{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700972 // This is a recursive method, but thinking about it "at the current level"
973 // it is a pretty simple flat list:
974 // <foo/>
975 // <!-- comment -->
976 //
977 // With a special case:
978 // <foo>
979 // </foo>
980 // <!-- comment -->
981 //
982 // Where the closing element (/foo) *must* be the next thing after the opening
983 // element, and the names must match. BUT the tricky bit is that the closing
984 // element will be read by the child.
985 //
986 // 'endTag' is the end tag for this node, it is returned by a call to a child.
987 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800988
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 while( p && *p ) {
990 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800991
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300993 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300994 if ( node == 0 ) {
995 break;
996 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997
kezenatore3531812016-11-29 19:49:07 +1000998 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000999
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001001 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001003 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001004 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001005 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 }
1007 break;
1008 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001009
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301010 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301011 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001012 // Declarations are only allowed at document level
1013 bool wellLocated = ( ToDocument() != 0 );
1014 if ( wellLocated ) {
1015 // Multiple declarations are allowed but all declarations
1016 // must occur before anything else
1017 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1018 if ( !existingNode->ToDeclaration() ) {
1019 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301020 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001021 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301022 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001023 }
1024 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001025 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001026 DeleteNode( node );
1027 break;
1028 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301029 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301030
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001031 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001033 // We read the end tag. Return it to the parent.
1034 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1035 if ( parentEnd ) {
1036 ele->_value.TransferTo( parentEnd );
1037 }
1038 node->_memPool->SetTracked(); // created and then immediately deleted.
1039 DeleteNode( node );
1040 return p;
1041 }
1042
1043 // Handle an end tag returned to this level.
1044 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001045 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001046 if ( endTag.Empty() ) {
1047 if ( ele->ClosingType() == XMLElement::OPEN ) {
1048 mismatch = true;
1049 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001051 else {
1052 if ( ele->ClosingType() != XMLElement::OPEN ) {
1053 mismatch = true;
1054 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001055 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001056 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 }
1058 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001059 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001060 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001061 DeleteNode( node );
1062 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001063 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 }
JayXondbfdd8f2014-12-12 20:07:14 -05001065 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001068}
1069
Dmitry-Mee3225b12014-09-03 11:03:11 +04001070void XMLNode::DeleteNode( XMLNode* node )
1071{
1072 if ( node == 0 ) {
1073 return;
1074 }
1075 MemPool* pool = node->_memPool;
1076 node->~XMLNode();
1077 pool->Free( node );
1078}
1079
Lee Thomason3cebdc42015-01-05 17:16:28 -08001080void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001081{
1082 TIXMLASSERT( insertThis );
1083 TIXMLASSERT( insertThis->_document == _document );
1084
1085 if ( insertThis->_parent )
1086 insertThis->_parent->Unlink( insertThis );
1087 else
1088 insertThis->_memPool->SetTracked();
1089}
1090
Dmitry-Meecb9b072016-10-12 16:44:59 +03001091const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1092{
1093 const XMLElement* element = this->ToElement();
1094 if ( element == 0 ) {
1095 return 0;
1096 }
1097 if ( name == 0 ) {
1098 return element;
1099 }
1100 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1101 return element;
1102 }
1103 return 0;
1104}
1105
Lee Thomason5492a1c2012-01-23 15:32:10 -08001106// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001107char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 const char* start = p;
1110 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001111 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001113 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 }
1115 return p;
1116 }
1117 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001118 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1119 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001120 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001122
kezenator4f756162016-11-29 19:46:27 +10001123 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001124 if ( p && *p ) {
1125 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001126 }
1127 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001128 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 }
1130 }
1131 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001132}
1133
1134
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001135XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1141 text->SetCData( this->CData() );
1142 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001143}
1144
1145
1146bool XMLText::ShallowEqual( const XMLNode* compare ) const
1147{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001148 const XMLText* text = compare->ToText();
1149 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001150}
1151
1152
Lee Thomason56bdd022012-02-09 18:16:58 -08001153bool XMLText::Accept( XMLVisitor* visitor ) const
1154{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001155 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001157}
1158
1159
Lee Thomason3f57d272012-01-11 15:30:03 -08001160// --------- XMLComment ---------- //
1161
Lee Thomasone4422302012-01-20 17:59:50 -08001162XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001163{
1164}
1165
1166
Lee Thomasonce0763e2012-01-11 15:43:54 -08001167XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001168{
Lee Thomason3f57d272012-01-11 15:30:03 -08001169}
1170
1171
kezenator4f756162016-11-29 19:46:27 +10001172char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 // Comment parses as text.
1175 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001176 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001178 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 }
1180 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001181}
1182
1183
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001184XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 }
1189 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1190 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001191}
1192
1193
1194bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1195{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001196 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001197 const XMLComment* comment = compare->ToComment();
1198 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001199}
1200
1201
Lee Thomason751da522012-02-10 08:50:51 -08001202bool XMLComment::Accept( XMLVisitor* visitor ) const
1203{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001204 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001206}
Lee Thomason56bdd022012-02-09 18:16:58 -08001207
1208
Lee Thomason50f97b22012-02-11 16:33:40 -08001209// --------- XMLDeclaration ---------- //
1210
1211XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1212{
1213}
1214
1215
1216XMLDeclaration::~XMLDeclaration()
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001219}
1220
1221
kezenator4f756162016-11-29 19:46:27 +10001222char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 // Declaration parses as text.
1225 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001226 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001228 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 }
1230 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001231}
1232
1233
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001234XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001237 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 }
1239 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1240 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001241}
1242
1243
1244bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1245{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001246 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001247 const XMLDeclaration* declaration = compare->ToDeclaration();
1248 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001249}
1250
1251
1252
Lee Thomason50f97b22012-02-11 16:33:40 -08001253bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1254{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001255 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
1259// --------- XMLUnknown ---------- //
1260
1261XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1262{
1263}
1264
1265
1266XMLUnknown::~XMLUnknown()
1267{
1268}
1269
1270
kezenator4f756162016-11-29 19:46:27 +10001271char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 // Unknown parses as text.
1274 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001275
kezenator4f756162016-11-29 19:46:27 +10001276 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001278 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 }
1280 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001281}
1282
1283
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001284XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001287 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 }
1289 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1290 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001291}
1292
1293
1294bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1295{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001296 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001297 const XMLUnknown* unknown = compare->ToUnknown();
1298 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001299}
1300
1301
Lee Thomason50f97b22012-02-11 16:33:40 -08001302bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1303{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001304 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001306}
1307
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001308// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001309
1310const char* XMLAttribute::Name() const
1311{
1312 return _name.GetStr();
1313}
1314
1315const char* XMLAttribute::Value() const
1316{
1317 return _value.GetStr();
1318}
1319
kezenator4f756162016-11-29 19:46:27 +10001320char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001323 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( !p || !*p ) {
1325 return 0;
1326 }
Lee Thomason22aead12012-01-23 13:29:35 -08001327
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001329 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001330 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return 0;
1332 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001333
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001335 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 if ( *p != '\"' && *p != '\'' ) {
1337 return 0;
1338 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001339
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 char endTag[2] = { *p, 0 };
1341 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001342
kezenator4f756162016-11-29 19:46:27 +10001343 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001345}
1346
1347
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001348void XMLAttribute::SetName( const char* n )
1349{
Lee Thomason624d43f2012-10-12 10:58:48 -07001350 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001351}
1352
1353
Lee Thomason2fa81722012-11-09 12:37:46 -08001354XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001357 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 }
1359 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001360}
1361
1362
Lee Thomason2fa81722012-11-09 12:37:46 -08001363XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001366 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 }
1368 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001369}
1370
1371
Lee Thomason51c12712016-06-04 20:18:49 -07001372XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1373{
1374 if (XMLUtil::ToInt64(Value(), value)) {
1375 return XML_SUCCESS;
1376 }
1377 return XML_WRONG_ATTRIBUTE_TYPE;
1378}
1379
1380
Lee Thomason2fa81722012-11-09 12:37:46 -08001381XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001384 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 }
1386 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001387}
1388
1389
Lee Thomason2fa81722012-11-09 12:37:46 -08001390XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001393 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 }
1395 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001396}
1397
1398
Lee Thomason2fa81722012-11-09 12:37:46 -08001399XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001402 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001405}
1406
1407
1408void XMLAttribute::SetAttribute( const char* v )
1409{
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001411}
1412
1413
Lee Thomason1ff38e02012-02-14 18:18:16 -08001414void XMLAttribute::SetAttribute( int v )
1415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 char buf[BUF_SIZE];
1417 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001419}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001420
1421
1422void XMLAttribute::SetAttribute( unsigned v )
1423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 char buf[BUF_SIZE];
1425 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427}
1428
1429
Lee Thomason51c12712016-06-04 20:18:49 -07001430void XMLAttribute::SetAttribute(int64_t v)
1431{
1432 char buf[BUF_SIZE];
1433 XMLUtil::ToStr(v, buf, BUF_SIZE);
1434 _value.SetStr(buf);
1435}
1436
1437
1438
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439void XMLAttribute::SetAttribute( bool v )
1440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 char buf[BUF_SIZE];
1442 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001444}
1445
1446void XMLAttribute::SetAttribute( double v )
1447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 char buf[BUF_SIZE];
1449 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001451}
1452
1453void XMLAttribute::SetAttribute( float v )
1454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458}
1459
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001460
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001461// --------- XMLElement ---------- //
1462XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _closingType( 0 ),
1464 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465{
1466}
1467
1468
1469XMLElement::~XMLElement()
1470{
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 while( _rootAttribute ) {
1472 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001473 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001476}
1477
1478
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001479const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1480{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001481 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1483 return a;
1484 }
1485 }
1486 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487}
1488
1489
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001490const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 const XMLAttribute* a = FindAttribute( name );
1493 if ( !a ) {
1494 return 0;
1495 }
1496 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1497 return a->Value();
1498 }
1499 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001500}
1501
Josh Wittnercf3dd092016-10-11 18:57:17 -07001502int XMLElement::IntAttribute(const char* name, int defaultValue) const
1503{
1504 int i = defaultValue;
1505 QueryIntAttribute(name, &i);
1506 return i;
1507}
1508
1509unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1510{
1511 unsigned i = defaultValue;
1512 QueryUnsignedAttribute(name, &i);
1513 return i;
1514}
1515
1516int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1517{
1518 int64_t i = defaultValue;
1519 QueryInt64Attribute(name, &i);
1520 return i;
1521}
1522
1523bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1524{
1525 bool b = defaultValue;
1526 QueryBoolAttribute(name, &b);
1527 return b;
1528}
1529
1530double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1531{
1532 double d = defaultValue;
1533 QueryDoubleAttribute(name, &d);
1534 return d;
1535}
1536
1537float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1538{
1539 float f = defaultValue;
1540 QueryFloatAttribute(name, &f);
1541 return f;
1542}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001543
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001544const char* XMLElement::GetText() const
1545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001547 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 }
1549 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001550}
1551
1552
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001553void XMLElement::SetText( const char* inText )
1554{
Uli Kusterer869bb592014-01-21 01:36:16 +01001555 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001556 FirstChild()->SetValue( inText );
1557 else {
1558 XMLText* theText = GetDocument()->NewText( inText );
1559 InsertFirstChild( theText );
1560 }
1561}
1562
Lee Thomason5bb2d802014-01-24 10:42:57 -08001563
1564void XMLElement::SetText( int v )
1565{
1566 char buf[BUF_SIZE];
1567 XMLUtil::ToStr( v, buf, BUF_SIZE );
1568 SetText( buf );
1569}
1570
1571
1572void XMLElement::SetText( unsigned v )
1573{
1574 char buf[BUF_SIZE];
1575 XMLUtil::ToStr( v, buf, BUF_SIZE );
1576 SetText( buf );
1577}
1578
1579
Lee Thomason51c12712016-06-04 20:18:49 -07001580void XMLElement::SetText(int64_t v)
1581{
1582 char buf[BUF_SIZE];
1583 XMLUtil::ToStr(v, buf, BUF_SIZE);
1584 SetText(buf);
1585}
1586
1587
1588void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001589{
1590 char buf[BUF_SIZE];
1591 XMLUtil::ToStr( v, buf, BUF_SIZE );
1592 SetText( buf );
1593}
1594
1595
1596void XMLElement::SetText( float v )
1597{
1598 char buf[BUF_SIZE];
1599 XMLUtil::ToStr( v, buf, BUF_SIZE );
1600 SetText( buf );
1601}
1602
1603
1604void XMLElement::SetText( double v )
1605{
1606 char buf[BUF_SIZE];
1607 XMLUtil::ToStr( v, buf, BUF_SIZE );
1608 SetText( buf );
1609}
1610
1611
MortenMacFly4ee49f12013-01-14 20:03:14 +01001612XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001615 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001616 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 return XML_SUCCESS;
1618 }
1619 return XML_CAN_NOT_CONVERT_TEXT;
1620 }
1621 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001622}
1623
1624
MortenMacFly4ee49f12013-01-14 20:03:14 +01001625XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001626{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001628 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001629 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 return XML_SUCCESS;
1631 }
1632 return XML_CAN_NOT_CONVERT_TEXT;
1633 }
1634 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001635}
1636
1637
Lee Thomason51c12712016-06-04 20:18:49 -07001638XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1639{
1640 if (FirstChild() && FirstChild()->ToText()) {
1641 const char* t = FirstChild()->Value();
1642 if (XMLUtil::ToInt64(t, ival)) {
1643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
1648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
MortenMacFly4ee49f12013-01-14 20:03:14 +01001664XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001665{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001667 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001668 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001674}
1675
1676
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001680 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001681 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 return XML_SUCCESS;
1683 }
1684 return XML_CAN_NOT_CONVERT_TEXT;
1685 }
1686 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001687}
1688
Josh Wittnercf3dd092016-10-11 18:57:17 -07001689int XMLElement::IntText(int defaultValue) const
1690{
1691 int i = defaultValue;
1692 QueryIntText(&i);
1693 return i;
1694}
1695
1696unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1697{
1698 unsigned i = defaultValue;
1699 QueryUnsignedText(&i);
1700 return i;
1701}
1702
1703int64_t XMLElement::Int64Text(int64_t defaultValue) const
1704{
1705 int64_t i = defaultValue;
1706 QueryInt64Text(&i);
1707 return i;
1708}
1709
1710bool XMLElement::BoolText(bool defaultValue) const
1711{
1712 bool b = defaultValue;
1713 QueryBoolText(&b);
1714 return b;
1715}
1716
1717double XMLElement::DoubleText(double defaultValue) const
1718{
1719 double d = defaultValue;
1720 QueryDoubleText(&d);
1721 return d;
1722}
1723
1724float XMLElement::FloatText(float defaultValue) const
1725{
1726 float f = defaultValue;
1727 QueryFloatText(&f);
1728 return f;
1729}
Lee Thomason21be8822012-07-15 17:27:22 -07001730
1731
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001732XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 XMLAttribute* last = 0;
1735 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1740 break;
1741 }
1742 }
1743 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001744 attrib = CreateAttribute();
1745 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001747 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 }
1750 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001751 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 }
1754 attrib->SetName( name );
1755 }
1756 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001757}
1758
1759
U-Stream\Leeae25a442012-02-17 17:48:16 -08001760void XMLElement::DeleteAttribute( const char* name )
1761{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1765 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001771 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 break;
1773 }
1774 prev = a;
1775 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001776}
1777
1778
kezenator4f756162016-11-29 19:46:27 +10001779char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001780{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 const char* start = p;
1782 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001783
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 // Read the attributes.
1785 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001786 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001787 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001788 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 return 0;
1790 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001791
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001793 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001794 XMLAttribute* attrib = CreateAttribute();
1795 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001796 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001797
kezenatorec694152016-11-26 17:21:43 +10001798 int attrLineNum = attrib->_parseLineNum;
1799
kezenator4f756162016-11-29 19:46:27 +10001800 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001802 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001803 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 return 0;
1805 }
1806 // There is a minor bug here: if the attribute in the source xml
1807 // document is duplicated, it will not be detected and the
1808 // attribute will be doubly added. However, tracking the 'prevAttribute'
1809 // avoids re-scanning the attribute list. Preferring performance for
1810 // now, may reconsider in the future.
1811 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001812 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001813 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 }
1815 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001816 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
1819 prevAttribute = attrib;
1820 }
1821 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 else if ( *p == '>' ) {
1823 ++p;
1824 break;
1825 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001826 // end of the tag
1827 else if ( *p == '/' && *(p+1) == '>' ) {
1828 _closingType = CLOSED;
1829 return p+2; // done; sealed element.
1830 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 else {
kezenatorec694152016-11-26 17:21:43 +10001832 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 return 0;
1834 }
1835 }
1836 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001837}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001838
Dmitry-Mee3225b12014-09-03 11:03:11 +04001839void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1840{
1841 if ( attribute == 0 ) {
1842 return;
1843 }
1844 MemPool* pool = attribute->_memPool;
1845 attribute->~XMLAttribute();
1846 pool->Free( attribute );
1847}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001848
Dmitry-Mea60caa22016-11-22 18:28:08 +03001849XMLAttribute* XMLElement::CreateAttribute()
1850{
1851 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1852 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1853 attrib->_memPool = &_document->_attributePool;
1854 attrib->_memPool->SetTracked();
1855 return attrib;
1856}
1857
Lee Thomason67d61312012-01-24 16:01:51 -08001858//
1859// <ele></ele>
1860// <ele>foo<b>bar</b></ele>
1861//
kezenator4f756162016-11-29 19:46:27 +10001862char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001863{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001865 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001866
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 // The closing element is the </element> form. It is
1868 // parsed just like a regular element then deleted from
1869 // the DOM.
1870 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 ++p;
1873 }
Lee Thomason67d61312012-01-24 16:01:51 -08001874
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 p = _value.ParseName( p );
1876 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 return 0;
1878 }
Lee Thomason67d61312012-01-24 16:01:51 -08001879
kezenator4f756162016-11-29 19:46:27 +10001880 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 return p;
1883 }
Lee Thomason67d61312012-01-24 16:01:51 -08001884
kezenator4f756162016-11-29 19:46:27 +10001885 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001887}
1888
1889
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001890
1891XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1892{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 }
1896 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1897 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1898 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1899 }
1900 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001901}
1902
1903
1904bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1905{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001906 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001908 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001909
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 const XMLAttribute* a=FirstAttribute();
1911 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001912
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 while ( a && b ) {
1914 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1915 return false;
1916 }
1917 a = a->Next();
1918 b = b->Next();
1919 }
1920 if ( a || b ) {
1921 // different count
1922 return false;
1923 }
1924 return true;
1925 }
1926 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927}
1928
1929
Lee Thomason751da522012-02-10 08:50:51 -08001930bool XMLElement::Accept( XMLVisitor* visitor ) const
1931{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001932 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1935 if ( !node->Accept( visitor ) ) {
1936 break;
1937 }
1938 }
1939 }
1940 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001941}
Lee Thomason56bdd022012-02-09 18:16:58 -08001942
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001943
Lee Thomason3f57d272012-01-11 15:30:03 -08001944// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001945
1946// Warning: List must match 'enum XMLError'
1947const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1948 "XML_SUCCESS",
1949 "XML_NO_ATTRIBUTE",
1950 "XML_WRONG_ATTRIBUTE_TYPE",
1951 "XML_ERROR_FILE_NOT_FOUND",
1952 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1953 "XML_ERROR_FILE_READ_ERROR",
1954 "XML_ERROR_ELEMENT_MISMATCH",
1955 "XML_ERROR_PARSING_ELEMENT",
1956 "XML_ERROR_PARSING_ATTRIBUTE",
1957 "XML_ERROR_IDENTIFYING_TAG",
1958 "XML_ERROR_PARSING_TEXT",
1959 "XML_ERROR_PARSING_CDATA",
1960 "XML_ERROR_PARSING_COMMENT",
1961 "XML_ERROR_PARSING_DECLARATION",
1962 "XML_ERROR_PARSING_UNKNOWN",
1963 "XML_ERROR_EMPTY_DOCUMENT",
1964 "XML_ERROR_MISMATCHED_ELEMENT",
1965 "XML_ERROR_PARSING",
1966 "XML_CAN_NOT_CONVERT_TEXT",
1967 "XML_NO_TEXT_NODE"
1968};
1969
1970
Lee Thomason624d43f2012-10-12 10:58:48 -07001971XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001973 _writeBOM( false ),
1974 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001975 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001978{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001979 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1980 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001981}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001982
1983
Lee Thomason3f57d272012-01-11 15:30:03 -08001984XMLDocument::~XMLDocument()
1985{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001986 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001987}
1988
1989
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001990void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001991{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001992 DeleteChildren();
1993
Dmitry-Meab37df82014-11-28 12:08:36 +03001994#ifdef DEBUG
1995 const bool hadError = Error();
1996#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001997 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001998
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 delete [] _charBuffer;
2000 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002001
2002#if 0
2003 _textPool.Trace( "text" );
2004 _elementPool.Trace( "element" );
2005 _commentPool.Trace( "comment" );
2006 _attributePool.Trace( "attribute" );
2007#endif
2008
2009#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002010 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002011 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2012 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2013 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2014 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2015 }
2016#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002017}
2018
Lee Thomason3f57d272012-01-11 15:30:03 -08002019
Lee Thomason2c85a712012-01-31 08:24:24 -08002020XMLElement* XMLDocument::NewElement( const char* name )
2021{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002022 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
2024 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 ele->SetName( name );
2026 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002027}
2028
2029
Lee Thomason1ff38e02012-02-14 18:18:16 -08002030XMLComment* XMLDocument::NewComment( const char* str )
2031{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002032 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
2034 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 comment->SetValue( str );
2036 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002037}
2038
2039
2040XMLText* XMLDocument::NewText( const char* str )
2041{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002042 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002043 XMLText* text = new (_textPool.Alloc()) XMLText( this );
2044 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 text->SetValue( str );
2046 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002047}
2048
2049
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002050XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2051{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002052 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2054 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2056 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002057}
2058
2059
2060XMLUnknown* XMLDocument::NewUnknown( const char* str )
2061{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002062 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2064 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 unk->SetValue( str );
2066 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002067}
2068
Dmitry-Me01578db2014-08-19 10:18:48 +04002069static FILE* callfopen( const char* filepath, const char* mode )
2070{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002071 TIXMLASSERT( filepath );
2072 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002073#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2074 FILE* fp = 0;
2075 errno_t err = fopen_s( &fp, filepath, mode );
2076 if ( err ) {
2077 return 0;
2078 }
2079#else
2080 FILE* fp = fopen( filepath, mode );
2081#endif
2082 return fp;
2083}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002084
2085void XMLDocument::DeleteNode( XMLNode* node ) {
2086 TIXMLASSERT( node );
2087 TIXMLASSERT(node->_document == this );
2088 if (node->_parent) {
2089 node->_parent->DeleteChild( node );
2090 }
2091 else {
2092 // Isn't in the tree.
2093 // Use the parent delete.
2094 // Also, we need to mark it tracked: we 'know'
2095 // it was never used.
2096 node->_memPool->SetTracked();
2097 // Call the static XMLNode version:
2098 XMLNode::DeleteNode(node);
2099 }
2100}
2101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102
Lee Thomason2fa81722012-11-09 12:37:46 -08002103XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002104{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002105 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002106 FILE* fp = callfopen( filename, "rb" );
2107 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002108 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 }
2111 LoadFile( fp );
2112 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002114}
2115
Dmitry-Me901fed52015-09-25 10:29:51 +03002116// This is likely overengineered template art to have a check that unsigned long value incremented
2117// by one still fits into size_t. If size_t type is larger than unsigned long type
2118// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2119// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2120// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2121// types sizes relate to each other.
2122template
2123<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2124struct LongFitsIntoSizeTMinusOne {
2125 static bool Fits( unsigned long value )
2126 {
2127 return value < (size_t)-1;
2128 }
2129};
2130
2131template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002132struct LongFitsIntoSizeTMinusOne<false> {
2133 static bool Fits( unsigned long )
2134 {
2135 return true;
2136 }
2137};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002138
Lee Thomason2fa81722012-11-09 12:37:46 -08002139XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002140{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002141 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002142
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002143 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002144 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002145 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002146 return _errorID;
2147 }
2148
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002150 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002152 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002153 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002154 return _errorID;
2155 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002156 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002157
Dmitry-Me901fed52015-09-25 10:29:51 +03002158 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002159 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002160 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002161 return _errorID;
2162 }
2163
Dmitry-Me72801b82015-05-07 09:41:39 +03002164 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002165 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002168
Dmitry-Me72801b82015-05-07 09:41:39 +03002169 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002170 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _charBuffer = new char[size+1];
2172 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002174 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002177
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002179
Dmitry-Me97476b72015-01-01 16:15:57 +03002180 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002182}
2183
2184
Lee Thomason2fa81722012-11-09 12:37:46 -08002185XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186{
Dmitry-Me01578db2014-08-19 10:18:48 +04002187 FILE* fp = callfopen( filename, "w" );
2188 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002189 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 }
2192 SaveFile(fp, compact);
2193 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002195}
2196
2197
Lee Thomason2fa81722012-11-09 12:37:46 -08002198XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002199{
Ant Mitchell189198f2015-03-24 16:20:36 +00002200 // Clear any error from the last save, otherwise it will get reported
2201 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002202 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 XMLPrinter stream( fp, compact );
2204 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002206}
2207
Lee Thomason1ff38e02012-02-14 18:18:16 -08002208
Lee Thomason2fa81722012-11-09 12:37:46 -08002209XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002210{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002211 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002212
Lee Thomason82d32002014-02-21 22:47:18 -08002213 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002214 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 }
2217 if ( len == (size_t)(-1) ) {
2218 len = strlen( p );
2219 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002220 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 _charBuffer = new char[ len+1 ];
2222 memcpy( _charBuffer, p, len );
2223 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002224
Dmitry-Me97476b72015-01-01 16:15:57 +03002225 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002226 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002227 // clean up now essentially dangling memory.
2228 // and the parse fail can put objects in the
2229 // pools that are dead and inaccessible.
2230 DeleteChildren();
2231 _elementPool.Clear();
2232 _attributePool.Clear();
2233 _textPool.Clear();
2234 _commentPool.Clear();
2235 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002237}
2238
2239
PKEuS1c5f99e2013-07-06 11:28:39 +02002240void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002241{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002242 if ( streamer ) {
2243 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002245 else {
2246 XMLPrinter stdoutStreamer( stdout );
2247 Accept( &stdoutStreamer );
2248 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002249}
2250
2251
kezenatorec694152016-11-26 17:21:43 +10002252void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002253{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002254 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002256
2257 _errorStr1.Reset();
2258 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002259 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002260
2261 if (str1)
2262 _errorStr1.SetStr(str1);
2263 if (str2)
2264 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002265}
2266
Lee Thomasone90e9012016-12-24 07:34:39 -08002267/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002268{
kezenator5a700712016-11-26 13:54:42 +10002269 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2270 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002271 TIXMLASSERT( errorName && errorName[0] );
2272 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002273}
Lee Thomason5cae8972012-01-24 18:03:07 -08002274
kezenator5a700712016-11-26 13:54:42 +10002275const char* XMLDocument::ErrorName() const
2276{
Lee Thomasone90e9012016-12-24 07:34:39 -08002277 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002278}
2279
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002280void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002281{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002282 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 static const int LEN = 20;
2284 char buf1[LEN] = { 0 };
2285 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002286
Lee Thomason584af572016-09-05 14:14:16 -07002287 if ( !_errorStr1.Empty() ) {
2288 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 }
Lee Thomason584af572016-09-05 14:14:16 -07002290 if ( !_errorStr2.Empty() ) {
2291 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293
Dmitry-Me2ad43202015-04-16 12:18:58 +03002294 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2295 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2296 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002297 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2298 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002300}
2301
Dmitry-Me97476b72015-01-01 16:15:57 +03002302void XMLDocument::Parse()
2303{
2304 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2305 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002306 _parseCurLineNum = 1;
2307 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002308 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002309 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002310 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002311 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002312 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002313 return;
2314 }
kezenator4f756162016-11-29 19:46:27 +10002315 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002316}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002317
PKEuS1bfb9542013-08-04 13:51:17 +02002318XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 _elementJustOpened( false ),
2320 _firstElement( true ),
2321 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002322 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002323 _textDepth( -1 ),
2324 _processEntities( true ),
2325 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002328 _entityFlag[i] = false;
2329 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002330 }
2331 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002332 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002333 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002334 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002336 _restrictedEntityFlag[(unsigned char)'&'] = true;
2337 _restrictedEntityFlag[(unsigned char)'<'] = true;
2338 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002339 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002340}
2341
2342
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002343void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002344{
2345 va_list va;
2346 va_start( va, format );
2347
Lee Thomason624d43f2012-10-12 10:58:48 -07002348 if ( _fp ) {
2349 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 }
2351 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002352 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 // Close out and re-start the va-args
2354 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002355 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002357 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002358 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002359 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002361 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002362}
2363
2364
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002365void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 for( int i=0; i<depth; ++i ) {
2368 Print( " " );
2369 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002370}
2371
2372
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002373void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 // Look for runs of bytes between entities to print.
2376 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002377
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002379 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002380 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002381 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 // Remember, char is sometimes signed. (How many times has that bitten me?)
2383 if ( *q > 0 && *q < ENTITY_RANGE ) {
2384 // Check for entities. If one is found, flush
2385 // the stream up until the entity, write the
2386 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002387 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002389 const size_t delta = q - p;
2390 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002391 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002392 Print( "%.*s", toPrint, p );
2393 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002395 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 for( int i=0; i<NUM_ENTITIES; ++i ) {
2397 if ( entities[i].value == *q ) {
2398 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002399 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 break;
2401 }
2402 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002403 if ( !entityPatternPrinted ) {
2404 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2405 TIXMLASSERT( false );
2406 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 ++p;
2408 }
2409 }
2410 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002411 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 }
2413 }
2414 // Flush the remaining string. This will be the entire
2415 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002416 TIXMLASSERT( p <= q );
2417 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 Print( "%s", p );
2419 }
Lee Thomason857b8682012-01-25 17:50:25 -08002420}
2421
U-Stream\Leeae25a442012-02-17 17:48:16 -08002422
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002423void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002426 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 -07002427 Print( "%s", bom );
2428 }
2429 if ( writeDec ) {
2430 PushDeclaration( "xml version=\"1.0\"" );
2431 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002432}
2433
2434
Uli Kusterer593a33d2014-02-01 12:48:51 +01002435void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002436{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002437 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002438 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002439
Uli Kusterer593a33d2014-02-01 12:48:51 +01002440 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002442 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002443 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002444 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002446
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002448 _elementJustOpened = true;
2449 _firstElement = false;
2450 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002451}
2452
2453
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002454void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002455{
Lee Thomason624d43f2012-10-12 10:58:48 -07002456 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 Print( " %s=\"", name );
2458 PrintString( value, false );
2459 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002460}
2461
2462
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002463void XMLPrinter::PushAttribute( const char* name, int v )
2464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 char buf[BUF_SIZE];
2466 XMLUtil::ToStr( v, buf, BUF_SIZE );
2467 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002468}
2469
2470
2471void XMLPrinter::PushAttribute( const char* name, unsigned v )
2472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002473 char buf[BUF_SIZE];
2474 XMLUtil::ToStr( v, buf, BUF_SIZE );
2475 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002476}
2477
2478
Lee Thomason51c12712016-06-04 20:18:49 -07002479void XMLPrinter::PushAttribute(const char* name, int64_t v)
2480{
2481 char buf[BUF_SIZE];
2482 XMLUtil::ToStr(v, buf, BUF_SIZE);
2483 PushAttribute(name, buf);
2484}
2485
2486
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002487void XMLPrinter::PushAttribute( const char* name, bool v )
2488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 char buf[BUF_SIZE];
2490 XMLUtil::ToStr( v, buf, BUF_SIZE );
2491 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002492}
2493
2494
2495void XMLPrinter::PushAttribute( const char* name, double v )
2496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002497 char buf[BUF_SIZE];
2498 XMLUtil::ToStr( v, buf, BUF_SIZE );
2499 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002500}
2501
2502
Uli Kustererca412e82014-02-01 13:35:05 +01002503void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002504{
Lee Thomason624d43f2012-10-12 10:58:48 -07002505 --_depth;
2506 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002507
Lee Thomason624d43f2012-10-12 10:58:48 -07002508 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002509 Print( "/>" );
2510 }
2511 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002512 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002513 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 }
2516 Print( "</%s>", name );
2517 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002518
Lee Thomason624d43f2012-10-12 10:58:48 -07002519 if ( _textDepth == _depth ) {
2520 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 }
Uli Kustererca412e82014-02-01 13:35:05 +01002522 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 Print( "\n" );
2524 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002525 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002526}
2527
2528
Dmitry-Mea092bc12014-12-23 17:57:05 +03002529void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002530{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002531 if ( !_elementJustOpened ) {
2532 return;
2533 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002534 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002536}
2537
2538
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002539void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002540{
Lee Thomason624d43f2012-10-12 10:58:48 -07002541 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002542
Dmitry-Mea092bc12014-12-23 17:57:05 +03002543 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002545 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 }
2547 else {
2548 PrintString( text, true );
2549 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002550}
2551
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002552void XMLPrinter::PushText( int64_t value )
2553{
2554 char buf[BUF_SIZE];
2555 XMLUtil::ToStr( value, buf, BUF_SIZE );
2556 PushText( buf, false );
2557}
2558
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002559void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 char buf[BUF_SIZE];
2562 XMLUtil::ToStr( value, buf, BUF_SIZE );
2563 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002564}
2565
2566
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002567void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002569 char buf[BUF_SIZE];
2570 XMLUtil::ToStr( value, buf, BUF_SIZE );
2571 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002572}
2573
2574
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002575void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002577 char buf[BUF_SIZE];
2578 XMLUtil::ToStr( value, buf, BUF_SIZE );
2579 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002580}
2581
2582
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002583void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002585 char buf[BUF_SIZE];
2586 XMLUtil::ToStr( value, buf, BUF_SIZE );
2587 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002588}
2589
2590
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002591void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 char buf[BUF_SIZE];
2594 XMLUtil::ToStr( value, buf, BUF_SIZE );
2595 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002596}
2597
Lee Thomason5cae8972012-01-24 18:03:07 -08002598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002599void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002600{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002601 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002602 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002603 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002604 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002606 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002607 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002608}
Lee Thomason751da522012-02-10 08:50:51 -08002609
2610
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002611void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002612{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002613 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002614 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002615 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002616 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002618 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002620}
2621
2622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002623void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002624{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002625 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002626 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002628 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002629 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002630 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002631 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002632}
2633
2634
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002635bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002636{
Lee Thomason624d43f2012-10-12 10:58:48 -07002637 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002638 if ( doc.HasBOM() ) {
2639 PushHeader( true, false );
2640 }
2641 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002642}
2643
2644
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002645bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002646{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002647 const XMLElement* parentElem = 0;
2648 if ( element.Parent() ) {
2649 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002650 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002651 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002652 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002653 while ( attribute ) {
2654 PushAttribute( attribute->Name(), attribute->Value() );
2655 attribute = attribute->Next();
2656 }
2657 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002658}
2659
2660
Uli Kustererca412e82014-02-01 13:35:05 +01002661bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002662{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002663 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002665}
2666
2667
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002668bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002669{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002670 PushText( text.Value(), text.CData() );
2671 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002672}
2673
2674
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002675bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002676{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002677 PushComment( comment.Value() );
2678 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002679}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002681bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002682{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002683 PushDeclaration( declaration.Value() );
2684 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002685}
2686
2687
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002688bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002689{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002690 PushUnknown( unknown.Value() );
2691 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002692}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002693
Lee Thomason685b8952012-11-12 13:00:06 -08002694} // namespace tinyxml2
2695