blob: 0d6e2bc20c7f66cd3bdf40683259843ea6983b80 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300681 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000682 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += xmlHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += commentHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p += cdataHeaderLen;
695 text->SetCData( true );
696 }
697 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += dtdHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += elementHeaderLen;
706 }
707 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000711 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Dmitry-Me02384662015-03-03 16:02:13 +0300714 TIXMLASSERT( returnNode );
715 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 *node = returnNode;
717 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718}
719
720
Lee Thomason751da522012-02-10 08:50:51 -0800721bool XMLDocument::Accept( XMLVisitor* visitor ) const
722{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300723 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( visitor->VisitEnter( *this ) ) {
725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
726 if ( !node->Accept( visitor ) ) {
727 break;
728 }
729 }
730 }
731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735// --------- XMLNode ----------- //
736
737XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _document( doc ),
739 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000740 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200742 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700743 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200744 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746}
747
748
749XMLNode::~XMLNode()
750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( _parent ) {
753 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755}
756
Michael Daumling21626882013-10-22 17:03:37 +0200757const char* XMLNode::Value() const
758{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300759 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530760 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530761 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200762 return _value.GetStr();
763}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800765void XMLNode::SetValue( const char* str, bool staticMem )
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800773}
774
775
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800776void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800777{
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300779 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300780 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800783}
784
785
786void XMLNode::Unlink( XMLNode* child )
787{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300788 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300789 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300790 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 if ( child == _firstChild ) {
792 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 if ( child == _lastChild ) {
795 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 }
Lee Thomasond923c672012-01-23 08:44:25 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 if ( child->_prev ) {
799 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 if ( child->_next ) {
802 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700804 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805}
806
807
U-Stream\Leeae25a442012-02-17 17:48:16 -0800808void XMLNode::DeleteChild( XMLNode* node )
809{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300810 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300811 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100813 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800815}
816
817
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800818XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
819{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300820 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300821 if ( addThis->_document != _document ) {
822 TIXMLASSERT( false );
823 return 0;
824 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800825 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 if ( _lastChild ) {
828 TIXMLASSERT( _firstChild );
829 TIXMLASSERT( _lastChild->_next == 0 );
830 _lastChild->_next = addThis;
831 addThis->_prev = _lastChild;
832 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
836 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 TIXMLASSERT( _firstChild == 0 );
838 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800839
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 addThis->_prev = 0;
841 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800845}
846
847
Lee Thomason1ff38e02012-02-14 18:18:16 -0800848XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
849{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300850 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 if ( addThis->_document != _document ) {
852 TIXMLASSERT( false );
853 return 0;
854 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800855 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( _firstChild ) {
858 TIXMLASSERT( _lastChild );
859 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 _firstChild->_prev = addThis;
862 addThis->_next = _firstChild;
863 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800864
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 }
867 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 TIXMLASSERT( _lastChild == 0 );
869 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 addThis->_prev = 0;
872 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400875 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876}
877
878
879XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
880{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300881 TIXMLASSERT( addThis );
882 if ( addThis->_document != _document ) {
883 TIXMLASSERT( false );
884 return 0;
885 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700886
Dmitry-Meabb2d042014-12-09 12:59:31 +0300887 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300890 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return 0;
892 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 // The last node or the only node.
896 return InsertEndChild( addThis );
897 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800898 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 addThis->_prev = afterThis;
900 addThis->_next = afterThis->_next;
901 afterThis->_next->_prev = addThis;
902 afterThis->_next = addThis;
903 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905}
906
907
908
909
Dmitry-Me886ad972015-07-22 11:00:51 +0300910const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800911{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300912 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300913 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300915 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 }
917 }
918 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800919}
920
921
Dmitry-Me886ad972015-07-22 11:00:51 +0300922const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800923{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300924 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300925 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300937 const XMLElement* element = node->ToElementWithName( name );
938 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800943}
944
945
Dmitry-Me886ad972015-07-22 11:00:51 +0300946const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300948 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300949 const XMLElement* element = node->ToElementWithName( name );
950 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400951 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 }
954 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
kezenator4f756162016-11-29 19:46:27 +1000958char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 // This is a recursive method, but thinking about it "at the current level"
961 // it is a pretty simple flat list:
962 // <foo/>
963 // <!-- comment -->
964 //
965 // With a special case:
966 // <foo>
967 // </foo>
968 // <!-- comment -->
969 //
970 // Where the closing element (/foo) *must* be the next thing after the opening
971 // element, and the names must match. BUT the tricky bit is that the closing
972 // element will be read by the child.
973 //
974 // 'endTag' is the end tag for this node, it is returned by a call to a child.
975 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 while( p && *p ) {
978 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800979
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300981 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300982 if ( node == 0 ) {
983 break;
984 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985
kezenatore3531812016-11-29 19:49:07 +1000986 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000987
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000989 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400991 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000993 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 break;
996 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530998 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530999 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001000 // Declarations are only allowed at document level
1001 bool wellLocated = ( ToDocument() != 0 );
1002 if ( wellLocated ) {
1003 // Multiple declarations are allowed but all declarations
1004 // must occur before anything else
1005 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1006 if ( !existingNode->ToDeclaration() ) {
1007 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301008 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001009 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301010 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001011 }
1012 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001013 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001014 DeleteNode( node );
1015 break;
1016 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301017 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301018
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001019 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001021 // We read the end tag. Return it to the parent.
1022 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1023 if ( parentEnd ) {
1024 ele->_value.TransferTo( parentEnd );
1025 }
1026 node->_memPool->SetTracked(); // created and then immediately deleted.
1027 DeleteNode( node );
1028 return p;
1029 }
1030
1031 // Handle an end tag returned to this level.
1032 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001033 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001034 if ( endTag.Empty() ) {
1035 if ( ele->ClosingType() == XMLElement::OPEN ) {
1036 mismatch = true;
1037 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001039 else {
1040 if ( ele->ClosingType() != XMLElement::OPEN ) {
1041 mismatch = true;
1042 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001043 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001044 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001047 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001048 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001049 DeleteNode( node );
1050 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001051 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
JayXondbfdd8f2014-12-12 20:07:14 -05001053 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 }
1055 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001056}
1057
Dmitry-Mee3225b12014-09-03 11:03:11 +04001058void XMLNode::DeleteNode( XMLNode* node )
1059{
1060 if ( node == 0 ) {
1061 return;
1062 }
1063 MemPool* pool = node->_memPool;
1064 node->~XMLNode();
1065 pool->Free( node );
1066}
1067
Lee Thomason3cebdc42015-01-05 17:16:28 -08001068void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001069{
1070 TIXMLASSERT( insertThis );
1071 TIXMLASSERT( insertThis->_document == _document );
1072
1073 if ( insertThis->_parent )
1074 insertThis->_parent->Unlink( insertThis );
1075 else
1076 insertThis->_memPool->SetTracked();
1077}
1078
Dmitry-Meecb9b072016-10-12 16:44:59 +03001079const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1080{
1081 const XMLElement* element = this->ToElement();
1082 if ( element == 0 ) {
1083 return 0;
1084 }
1085 if ( name == 0 ) {
1086 return element;
1087 }
1088 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1089 return element;
1090 }
1091 return 0;
1092}
1093
Lee Thomason5492a1c2012-01-23 15:32:10 -08001094// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001095char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 const char* start = p;
1098 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001099 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001101 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 }
1103 return p;
1104 }
1105 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1107 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001108 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001110
kezenator4f756162016-11-29 19:46:27 +10001111 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( p && *p ) {
1113 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001114 }
1115 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001116 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 }
1118 }
1119 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001120}
1121
1122
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1129 text->SetCData( this->CData() );
1130 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
1134bool XMLText::ShallowEqual( const XMLNode* compare ) const
1135{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001136 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001137 const XMLText* text = compare->ToText();
1138 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001139}
1140
1141
Lee Thomason56bdd022012-02-09 18:16:58 -08001142bool XMLText::Accept( XMLVisitor* visitor ) const
1143{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001144 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001146}
1147
1148
Lee Thomason3f57d272012-01-11 15:30:03 -08001149// --------- XMLComment ---------- //
1150
Lee Thomasone4422302012-01-20 17:59:50 -08001151XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001152{
1153}
1154
1155
Lee Thomasonce0763e2012-01-11 15:43:54 -08001156XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001157{
Lee Thomason3f57d272012-01-11 15:30:03 -08001158}
1159
1160
kezenator4f756162016-11-29 19:46:27 +10001161char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 // Comment parses as text.
1164 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001165 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001167 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 }
1169 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001170}
1171
1172
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001173XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001176 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 }
1178 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1179 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001180}
1181
1182
1183bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1184{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001185 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001186 const XMLComment* comment = compare->ToComment();
1187 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001188}
1189
1190
Lee Thomason751da522012-02-10 08:50:51 -08001191bool XMLComment::Accept( XMLVisitor* visitor ) const
1192{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001193 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001195}
Lee Thomason56bdd022012-02-09 18:16:58 -08001196
1197
Lee Thomason50f97b22012-02-11 16:33:40 -08001198// --------- XMLDeclaration ---------- //
1199
1200XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1201{
1202}
1203
1204
1205XMLDeclaration::~XMLDeclaration()
1206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001208}
1209
1210
kezenator4f756162016-11-29 19:46:27 +10001211char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 // Declaration parses as text.
1214 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001215 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001217 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 }
1219 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001220}
1221
1222
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001223XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001226 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 }
1228 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1229 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001230}
1231
1232
1233bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1234{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001235 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001236 const XMLDeclaration* declaration = compare->ToDeclaration();
1237 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001238}
1239
1240
1241
Lee Thomason50f97b22012-02-11 16:33:40 -08001242bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1243{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001244 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001246}
1247
1248// --------- XMLUnknown ---------- //
1249
1250XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1251{
1252}
1253
1254
1255XMLUnknown::~XMLUnknown()
1256{
1257}
1258
1259
kezenator4f756162016-11-29 19:46:27 +10001260char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 // Unknown parses as text.
1263 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001264
kezenator4f756162016-11-29 19:46:27 +10001265 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001267 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 }
1269 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001270}
1271
1272
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001273XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 }
1278 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1279 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001280}
1281
1282
1283bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1284{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001285 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001286 const XMLUnknown* unknown = compare->ToUnknown();
1287 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001288}
1289
1290
Lee Thomason50f97b22012-02-11 16:33:40 -08001291bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1292{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001293 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001295}
1296
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001297// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001298
1299const char* XMLAttribute::Name() const
1300{
1301 return _name.GetStr();
1302}
1303
1304const char* XMLAttribute::Value() const
1305{
1306 return _value.GetStr();
1307}
1308
kezenator4f756162016-11-29 19:46:27 +10001309char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001310{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 if ( !p || !*p ) {
1314 return 0;
1315 }
Lee Thomason22aead12012-01-23 13:29:35 -08001316
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001318 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001319 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 return 0;
1321 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001322
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001324 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001325 if ( *p != '\"' && *p != '\'' ) {
1326 return 0;
1327 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001328
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 char endTag[2] = { *p, 0 };
1330 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001331
kezenator4f756162016-11-29 19:46:27 +10001332 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334}
1335
1336
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001337void XMLAttribute::SetName( const char* n )
1338{
Lee Thomason624d43f2012-10-12 10:58:48 -07001339 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001340}
1341
1342
Lee Thomason2fa81722012-11-09 12:37:46 -08001343XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001346 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 }
1348 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001349}
1350
1351
Lee Thomason2fa81722012-11-09 12:37:46 -08001352XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001355 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 }
1357 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001358}
1359
1360
Lee Thomason51c12712016-06-04 20:18:49 -07001361XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1362{
1363 if (XMLUtil::ToInt64(Value(), value)) {
1364 return XML_SUCCESS;
1365 }
1366 return XML_WRONG_ATTRIBUTE_TYPE;
1367}
1368
1369
Lee Thomason2fa81722012-11-09 12:37:46 -08001370XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001373 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 }
1375 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001376}
1377
1378
Lee Thomason2fa81722012-11-09 12:37:46 -08001379XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001382 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 }
1384 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001385}
1386
1387
Lee Thomason2fa81722012-11-09 12:37:46 -08001388XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001391 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 }
1393 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001394}
1395
1396
1397void XMLAttribute::SetAttribute( const char* v )
1398{
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001400}
1401
1402
Lee Thomason1ff38e02012-02-14 18:18:16 -08001403void XMLAttribute::SetAttribute( int v )
1404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 char buf[BUF_SIZE];
1406 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001407 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001408}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001409
1410
1411void XMLAttribute::SetAttribute( unsigned v )
1412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 char buf[BUF_SIZE];
1414 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416}
1417
1418
Lee Thomason51c12712016-06-04 20:18:49 -07001419void XMLAttribute::SetAttribute(int64_t v)
1420{
1421 char buf[BUF_SIZE];
1422 XMLUtil::ToStr(v, buf, BUF_SIZE);
1423 _value.SetStr(buf);
1424}
1425
1426
1427
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001428void XMLAttribute::SetAttribute( bool v )
1429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 char buf[BUF_SIZE];
1431 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001433}
1434
1435void XMLAttribute::SetAttribute( double v )
1436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 char buf[BUF_SIZE];
1438 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440}
1441
1442void XMLAttribute::SetAttribute( float v )
1443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 char buf[BUF_SIZE];
1445 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001447}
1448
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001449
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001450// --------- XMLElement ---------- //
1451XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001452 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001454{
1455}
1456
1457
1458XMLElement::~XMLElement()
1459{
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 while( _rootAttribute ) {
1461 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001462 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465}
1466
1467
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001468const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1469{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001470 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1472 return a;
1473 }
1474 }
1475 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001476}
1477
1478
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001479const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 const XMLAttribute* a = FindAttribute( name );
1482 if ( !a ) {
1483 return 0;
1484 }
1485 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1486 return a->Value();
1487 }
1488 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001489}
1490
Josh Wittnercf3dd092016-10-11 18:57:17 -07001491int XMLElement::IntAttribute(const char* name, int defaultValue) const
1492{
1493 int i = defaultValue;
1494 QueryIntAttribute(name, &i);
1495 return i;
1496}
1497
1498unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1499{
1500 unsigned i = defaultValue;
1501 QueryUnsignedAttribute(name, &i);
1502 return i;
1503}
1504
1505int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1506{
1507 int64_t i = defaultValue;
1508 QueryInt64Attribute(name, &i);
1509 return i;
1510}
1511
1512bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1513{
1514 bool b = defaultValue;
1515 QueryBoolAttribute(name, &b);
1516 return b;
1517}
1518
1519double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1520{
1521 double d = defaultValue;
1522 QueryDoubleAttribute(name, &d);
1523 return d;
1524}
1525
1526float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1527{
1528 float f = defaultValue;
1529 QueryFloatAttribute(name, &f);
1530 return f;
1531}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001532
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001533const char* XMLElement::GetText() const
1534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001536 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 }
1538 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001539}
1540
1541
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001542void XMLElement::SetText( const char* inText )
1543{
Uli Kusterer869bb592014-01-21 01:36:16 +01001544 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001545 FirstChild()->SetValue( inText );
1546 else {
1547 XMLText* theText = GetDocument()->NewText( inText );
1548 InsertFirstChild( theText );
1549 }
1550}
1551
Lee Thomason5bb2d802014-01-24 10:42:57 -08001552
1553void XMLElement::SetText( int v )
1554{
1555 char buf[BUF_SIZE];
1556 XMLUtil::ToStr( v, buf, BUF_SIZE );
1557 SetText( buf );
1558}
1559
1560
1561void XMLElement::SetText( unsigned v )
1562{
1563 char buf[BUF_SIZE];
1564 XMLUtil::ToStr( v, buf, BUF_SIZE );
1565 SetText( buf );
1566}
1567
1568
Lee Thomason51c12712016-06-04 20:18:49 -07001569void XMLElement::SetText(int64_t v)
1570{
1571 char buf[BUF_SIZE];
1572 XMLUtil::ToStr(v, buf, BUF_SIZE);
1573 SetText(buf);
1574}
1575
1576
1577void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001578{
1579 char buf[BUF_SIZE];
1580 XMLUtil::ToStr( v, buf, BUF_SIZE );
1581 SetText( buf );
1582}
1583
1584
1585void XMLElement::SetText( float v )
1586{
1587 char buf[BUF_SIZE];
1588 XMLUtil::ToStr( v, buf, BUF_SIZE );
1589 SetText( buf );
1590}
1591
1592
1593void XMLElement::SetText( double v )
1594{
1595 char buf[BUF_SIZE];
1596 XMLUtil::ToStr( v, buf, BUF_SIZE );
1597 SetText( buf );
1598}
1599
1600
MortenMacFly4ee49f12013-01-14 20:03:14 +01001601XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001604 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001605 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 return XML_SUCCESS;
1607 }
1608 return XML_CAN_NOT_CONVERT_TEXT;
1609 }
1610 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001611}
1612
1613
MortenMacFly4ee49f12013-01-14 20:03:14 +01001614XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001617 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001618 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 return XML_SUCCESS;
1620 }
1621 return XML_CAN_NOT_CONVERT_TEXT;
1622 }
1623 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001624}
1625
1626
Lee Thomason51c12712016-06-04 20:18:49 -07001627XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1628{
1629 if (FirstChild() && FirstChild()->ToText()) {
1630 const char* t = FirstChild()->Value();
1631 if (XMLUtil::ToInt64(t, ival)) {
1632 return XML_SUCCESS;
1633 }
1634 return XML_CAN_NOT_CONVERT_TEXT;
1635 }
1636 return XML_NO_TEXT_NODE;
1637}
1638
1639
MortenMacFly4ee49f12013-01-14 20:03:14 +01001640XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001641{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001643 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001644 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 return XML_SUCCESS;
1646 }
1647 return XML_CAN_NOT_CONVERT_TEXT;
1648 }
1649 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001650}
1651
1652
MortenMacFly4ee49f12013-01-14 20:03:14 +01001653XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001654{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001656 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001657 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 return XML_SUCCESS;
1659 }
1660 return XML_CAN_NOT_CONVERT_TEXT;
1661 }
1662 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001663}
1664
1665
MortenMacFly4ee49f12013-01-14 20:03:14 +01001666XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001667{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001669 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001670 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 return XML_SUCCESS;
1672 }
1673 return XML_CAN_NOT_CONVERT_TEXT;
1674 }
1675 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001676}
1677
Josh Wittnercf3dd092016-10-11 18:57:17 -07001678int XMLElement::IntText(int defaultValue) const
1679{
1680 int i = defaultValue;
1681 QueryIntText(&i);
1682 return i;
1683}
1684
1685unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1686{
1687 unsigned i = defaultValue;
1688 QueryUnsignedText(&i);
1689 return i;
1690}
1691
1692int64_t XMLElement::Int64Text(int64_t defaultValue) const
1693{
1694 int64_t i = defaultValue;
1695 QueryInt64Text(&i);
1696 return i;
1697}
1698
1699bool XMLElement::BoolText(bool defaultValue) const
1700{
1701 bool b = defaultValue;
1702 QueryBoolText(&b);
1703 return b;
1704}
1705
1706double XMLElement::DoubleText(double defaultValue) const
1707{
1708 double d = defaultValue;
1709 QueryDoubleText(&d);
1710 return d;
1711}
1712
1713float XMLElement::FloatText(float defaultValue) const
1714{
1715 float f = defaultValue;
1716 QueryFloatText(&f);
1717 return f;
1718}
Lee Thomason21be8822012-07-15 17:27:22 -07001719
1720
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001721XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1722{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 XMLAttribute* last = 0;
1724 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1729 break;
1730 }
1731 }
1732 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001733 attrib = CreateAttribute();
1734 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001736 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 }
1739 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001740 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 }
1743 attrib->SetName( name );
1744 }
1745 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001746}
1747
1748
U-Stream\Leeae25a442012-02-17 17:48:16 -08001749void XMLElement::DeleteAttribute( const char* name )
1750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1754 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 }
1757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001760 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 break;
1762 }
1763 prev = a;
1764 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001765}
1766
1767
kezenator4f756162016-11-29 19:46:27 +10001768char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001769{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 const char* start = p;
1771 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001772
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 // Read the attributes.
1774 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001775 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001776 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001777 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 return 0;
1779 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001780
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001782 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001783 XMLAttribute* attrib = CreateAttribute();
1784 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001785 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001786
kezenatorec694152016-11-26 17:21:43 +10001787 int attrLineNum = attrib->_parseLineNum;
1788
kezenator4f756162016-11-29 19:46:27 +10001789 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001791 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001792 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 return 0;
1794 }
1795 // There is a minor bug here: if the attribute in the source xml
1796 // document is duplicated, it will not be detected and the
1797 // attribute will be doubly added. However, tracking the 'prevAttribute'
1798 // avoids re-scanning the attribute list. Preferring performance for
1799 // now, may reconsider in the future.
1800 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001801 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 }
1804 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001805 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 }
1808 prevAttribute = attrib;
1809 }
1810 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 else if ( *p == '>' ) {
1812 ++p;
1813 break;
1814 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001815 // end of the tag
1816 else if ( *p == '/' && *(p+1) == '>' ) {
1817 _closingType = CLOSED;
1818 return p+2; // done; sealed element.
1819 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 else {
kezenatorec694152016-11-26 17:21:43 +10001821 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 return 0;
1823 }
1824 }
1825 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001826}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001827
Dmitry-Mee3225b12014-09-03 11:03:11 +04001828void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1829{
1830 if ( attribute == 0 ) {
1831 return;
1832 }
1833 MemPool* pool = attribute->_memPool;
1834 attribute->~XMLAttribute();
1835 pool->Free( attribute );
1836}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001837
Dmitry-Mea60caa22016-11-22 18:28:08 +03001838XMLAttribute* XMLElement::CreateAttribute()
1839{
1840 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1841 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001842 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001843 attrib->_memPool = &_document->_attributePool;
1844 attrib->_memPool->SetTracked();
1845 return attrib;
1846}
1847
Lee Thomason67d61312012-01-24 16:01:51 -08001848//
1849// <ele></ele>
1850// <ele>foo<b>bar</b></ele>
1851//
kezenator4f756162016-11-29 19:46:27 +10001852char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001853{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001855 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001856
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 // The closing element is the </element> form. It is
1858 // parsed just like a regular element then deleted from
1859 // the DOM.
1860 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 ++p;
1863 }
Lee Thomason67d61312012-01-24 16:01:51 -08001864
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 p = _value.ParseName( p );
1866 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 return 0;
1868 }
Lee Thomason67d61312012-01-24 16:01:51 -08001869
kezenator4f756162016-11-29 19:46:27 +10001870 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001871 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 return p;
1873 }
Lee Thomason67d61312012-01-24 16:01:51 -08001874
kezenator4f756162016-11-29 19:46:27 +10001875 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001877}
1878
1879
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001880
1881XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1882{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 }
1886 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1887 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1888 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1889 }
1890 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001891}
1892
1893
1894bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1895{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001896 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001898 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001899
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 const XMLAttribute* a=FirstAttribute();
1901 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001902
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 while ( a && b ) {
1904 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1905 return false;
1906 }
1907 a = a->Next();
1908 b = b->Next();
1909 }
1910 if ( a || b ) {
1911 // different count
1912 return false;
1913 }
1914 return true;
1915 }
1916 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001917}
1918
1919
Lee Thomason751da522012-02-10 08:50:51 -08001920bool XMLElement::Accept( XMLVisitor* visitor ) const
1921{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001922 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1925 if ( !node->Accept( visitor ) ) {
1926 break;
1927 }
1928 }
1929 }
1930 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001931}
Lee Thomason56bdd022012-02-09 18:16:58 -08001932
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001933
Lee Thomason3f57d272012-01-11 15:30:03 -08001934// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001935
1936// Warning: List must match 'enum XMLError'
1937const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1938 "XML_SUCCESS",
1939 "XML_NO_ATTRIBUTE",
1940 "XML_WRONG_ATTRIBUTE_TYPE",
1941 "XML_ERROR_FILE_NOT_FOUND",
1942 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1943 "XML_ERROR_FILE_READ_ERROR",
1944 "XML_ERROR_ELEMENT_MISMATCH",
1945 "XML_ERROR_PARSING_ELEMENT",
1946 "XML_ERROR_PARSING_ATTRIBUTE",
1947 "XML_ERROR_IDENTIFYING_TAG",
1948 "XML_ERROR_PARSING_TEXT",
1949 "XML_ERROR_PARSING_CDATA",
1950 "XML_ERROR_PARSING_COMMENT",
1951 "XML_ERROR_PARSING_DECLARATION",
1952 "XML_ERROR_PARSING_UNKNOWN",
1953 "XML_ERROR_EMPTY_DOCUMENT",
1954 "XML_ERROR_MISMATCHED_ELEMENT",
1955 "XML_ERROR_PARSING",
1956 "XML_CAN_NOT_CONVERT_TEXT",
1957 "XML_NO_TEXT_NODE"
1958};
1959
1960
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001961XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 _writeBOM( false ),
1964 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001965 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001966 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001967 _errorLineNum( 0 ),
1968 _charBuffer( 0 ),
1969 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001970{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001971 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1972 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001973}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001974
1975
Lee Thomason3f57d272012-01-11 15:30:03 -08001976XMLDocument::~XMLDocument()
1977{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001978 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001979}
1980
1981
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001982void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001983{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001984 DeleteChildren();
1985
Dmitry-Meab37df82014-11-28 12:08:36 +03001986#ifdef DEBUG
1987 const bool hadError = Error();
1988#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001989 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001990
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 delete [] _charBuffer;
1992 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001993
1994#if 0
1995 _textPool.Trace( "text" );
1996 _elementPool.Trace( "element" );
1997 _commentPool.Trace( "comment" );
1998 _attributePool.Trace( "attribute" );
1999#endif
2000
2001#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002002 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002003 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2004 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2005 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2006 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2007 }
2008#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002009}
2010
Lee Thomason3f57d272012-01-11 15:30:03 -08002011
Lee Thomason2c85a712012-01-31 08:24:24 -08002012XMLElement* XMLDocument::NewElement( const char* name )
2013{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002014 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 ele->SetName( name );
2016 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002017}
2018
2019
Lee Thomason1ff38e02012-02-14 18:18:16 -08002020XMLComment* XMLDocument::NewComment( const char* str )
2021{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002022 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 comment->SetValue( str );
2024 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002025}
2026
2027
2028XMLText* XMLDocument::NewText( const char* str )
2029{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002030 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 text->SetValue( str );
2032 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002033}
2034
2035
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002036XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2037{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002038 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2040 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002041}
2042
2043
2044XMLUnknown* XMLDocument::NewUnknown( const char* str )
2045{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002046 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 unk->SetValue( str );
2048 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002049}
2050
Dmitry-Me01578db2014-08-19 10:18:48 +04002051static FILE* callfopen( const char* filepath, const char* mode )
2052{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002053 TIXMLASSERT( filepath );
2054 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002055#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2056 FILE* fp = 0;
2057 errno_t err = fopen_s( &fp, filepath, mode );
2058 if ( err ) {
2059 return 0;
2060 }
2061#else
2062 FILE* fp = fopen( filepath, mode );
2063#endif
2064 return fp;
2065}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002066
2067void XMLDocument::DeleteNode( XMLNode* node ) {
2068 TIXMLASSERT( node );
2069 TIXMLASSERT(node->_document == this );
2070 if (node->_parent) {
2071 node->_parent->DeleteChild( node );
2072 }
2073 else {
2074 // Isn't in the tree.
2075 // Use the parent delete.
2076 // Also, we need to mark it tracked: we 'know'
2077 // it was never used.
2078 node->_memPool->SetTracked();
2079 // Call the static XMLNode version:
2080 XMLNode::DeleteNode(node);
2081 }
2082}
2083
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002084
Lee Thomason2fa81722012-11-09 12:37:46 -08002085XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002087 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002088 FILE* fp = callfopen( filename, "rb" );
2089 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002090 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 }
2093 LoadFile( fp );
2094 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002096}
2097
Dmitry-Me901fed52015-09-25 10:29:51 +03002098// This is likely overengineered template art to have a check that unsigned long value incremented
2099// by one still fits into size_t. If size_t type is larger than unsigned long type
2100// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2101// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2102// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2103// types sizes relate to each other.
2104template
2105<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2106struct LongFitsIntoSizeTMinusOne {
2107 static bool Fits( unsigned long value )
2108 {
2109 return value < (size_t)-1;
2110 }
2111};
2112
2113template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002114struct LongFitsIntoSizeTMinusOne<false> {
2115 static bool Fits( unsigned long )
2116 {
2117 return true;
2118 }
2119};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002120
Lee Thomason2fa81722012-11-09 12:37:46 -08002121XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002122{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002123 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002124
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002125 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002126 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002127 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002128 return _errorID;
2129 }
2130
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002132 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002134 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002135 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002136 return _errorID;
2137 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002138 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002139
Dmitry-Me901fed52015-09-25 10:29:51 +03002140 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002141 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002142 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002143 return _errorID;
2144 }
2145
Dmitry-Me72801b82015-05-07 09:41:39 +03002146 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002147 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002150
Dmitry-Me72801b82015-05-07 09:41:39 +03002151 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002152 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 _charBuffer = new char[size+1];
2154 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002156 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002159
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002161
Dmitry-Me97476b72015-01-01 16:15:57 +03002162 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002164}
2165
2166
Lee Thomason2fa81722012-11-09 12:37:46 -08002167XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002168{
Dmitry-Me01578db2014-08-19 10:18:48 +04002169 FILE* fp = callfopen( filename, "w" );
2170 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002171 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 }
2174 SaveFile(fp, compact);
2175 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002177}
2178
2179
Lee Thomason2fa81722012-11-09 12:37:46 -08002180XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002181{
Ant Mitchell189198f2015-03-24 16:20:36 +00002182 // Clear any error from the last save, otherwise it will get reported
2183 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002184 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 XMLPrinter stream( fp, compact );
2186 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188}
2189
Lee Thomason1ff38e02012-02-14 18:18:16 -08002190
Lee Thomason2fa81722012-11-09 12:37:46 -08002191XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002192{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002193 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002194
Lee Thomason82d32002014-02-21 22:47:18 -08002195 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002196 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 }
2199 if ( len == (size_t)(-1) ) {
2200 len = strlen( p );
2201 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002202 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 _charBuffer = new char[ len+1 ];
2204 memcpy( _charBuffer, p, len );
2205 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002206
Dmitry-Me97476b72015-01-01 16:15:57 +03002207 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002208 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002209 // clean up now essentially dangling memory.
2210 // and the parse fail can put objects in the
2211 // pools that are dead and inaccessible.
2212 DeleteChildren();
2213 _elementPool.Clear();
2214 _attributePool.Clear();
2215 _textPool.Clear();
2216 _commentPool.Clear();
2217 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002219}
2220
2221
PKEuS1c5f99e2013-07-06 11:28:39 +02002222void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002223{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002224 if ( streamer ) {
2225 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002227 else {
2228 XMLPrinter stdoutStreamer( stdout );
2229 Accept( &stdoutStreamer );
2230 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002231}
2232
2233
kezenatorec694152016-11-26 17:21:43 +10002234void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002235{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002236 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002238
2239 _errorStr1.Reset();
2240 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002241 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002242
2243 if (str1)
2244 _errorStr1.SetStr(str1);
2245 if (str2)
2246 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002247}
2248
Lee Thomasone90e9012016-12-24 07:34:39 -08002249/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002250{
kezenator5a700712016-11-26 13:54:42 +10002251 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2252 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002253 TIXMLASSERT( errorName && errorName[0] );
2254 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002255}
Lee Thomason5cae8972012-01-24 18:03:07 -08002256
kezenator5a700712016-11-26 13:54:42 +10002257const char* XMLDocument::ErrorName() const
2258{
Lee Thomasone90e9012016-12-24 07:34:39 -08002259 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002260}
2261
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002262void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002263{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002264 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 static const int LEN = 20;
2266 char buf1[LEN] = { 0 };
2267 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002268
Lee Thomason584af572016-09-05 14:14:16 -07002269 if ( !_errorStr1.Empty() ) {
2270 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 }
Lee Thomason584af572016-09-05 14:14:16 -07002272 if ( !_errorStr2.Empty() ) {
2273 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002275
Dmitry-Me2ad43202015-04-16 12:18:58 +03002276 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2277 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2278 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002279 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2280 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282}
2283
Dmitry-Me97476b72015-01-01 16:15:57 +03002284void XMLDocument::Parse()
2285{
2286 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2287 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002288 _parseCurLineNum = 1;
2289 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002290 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002291 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002292 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002293 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002294 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002295 return;
2296 }
kezenator4f756162016-11-29 19:46:27 +10002297 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002298}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299
PKEuS1bfb9542013-08-04 13:51:17 +02002300XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 _elementJustOpened( false ),
2302 _firstElement( true ),
2303 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002304 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002305 _textDepth( -1 ),
2306 _processEntities( true ),
2307 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _entityFlag[i] = false;
2311 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 }
2313 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002314 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002315 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002316 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002318 _restrictedEntityFlag[(unsigned char)'&'] = true;
2319 _restrictedEntityFlag[(unsigned char)'<'] = true;
2320 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002321 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002322}
2323
2324
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002325void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002326{
2327 va_list va;
2328 va_start( va, format );
2329
Lee Thomason624d43f2012-10-12 10:58:48 -07002330 if ( _fp ) {
2331 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002332 }
2333 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002334 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 // Close out and re-start the va-args
2336 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002337 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002339 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002340 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002341 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002343 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002344}
2345
2346
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002347void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 for( int i=0; i<depth; ++i ) {
2350 Print( " " );
2351 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002352}
2353
2354
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002355void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 // Look for runs of bytes between entities to print.
2358 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002359
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002361 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002363 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 // Remember, char is sometimes signed. (How many times has that bitten me?)
2365 if ( *q > 0 && *q < ENTITY_RANGE ) {
2366 // Check for entities. If one is found, flush
2367 // the stream up until the entity, write the
2368 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002369 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002371 const size_t delta = q - p;
2372 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002373 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002374 Print( "%.*s", toPrint, p );
2375 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002377 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 for( int i=0; i<NUM_ENTITIES; ++i ) {
2379 if ( entities[i].value == *q ) {
2380 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002381 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 break;
2383 }
2384 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002385 if ( !entityPatternPrinted ) {
2386 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2387 TIXMLASSERT( false );
2388 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 ++p;
2390 }
2391 }
2392 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002393 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 }
2395 }
2396 // Flush the remaining string. This will be the entire
2397 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002398 TIXMLASSERT( p <= q );
2399 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 Print( "%s", p );
2401 }
Lee Thomason857b8682012-01-25 17:50:25 -08002402}
2403
U-Stream\Leeae25a442012-02-17 17:48:16 -08002404
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002405void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002408 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 -07002409 Print( "%s", bom );
2410 }
2411 if ( writeDec ) {
2412 PushDeclaration( "xml version=\"1.0\"" );
2413 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002414}
2415
2416
Uli Kusterer593a33d2014-02-01 12:48:51 +01002417void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002418{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002419 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002420 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002421
Uli Kusterer593a33d2014-02-01 12:48:51 +01002422 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002424 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002425 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002426 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002428
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002429 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002430 _elementJustOpened = true;
2431 _firstElement = false;
2432 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002433}
2434
2435
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002436void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002437{
Lee Thomason624d43f2012-10-12 10:58:48 -07002438 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 Print( " %s=\"", name );
2440 PrintString( value, false );
2441 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002442}
2443
2444
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002445void XMLPrinter::PushAttribute( const char* name, int v )
2446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 char buf[BUF_SIZE];
2448 XMLUtil::ToStr( v, buf, BUF_SIZE );
2449 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002450}
2451
2452
2453void XMLPrinter::PushAttribute( const char* name, unsigned v )
2454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 char buf[BUF_SIZE];
2456 XMLUtil::ToStr( v, buf, BUF_SIZE );
2457 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002458}
2459
2460
Lee Thomason51c12712016-06-04 20:18:49 -07002461void XMLPrinter::PushAttribute(const char* name, int64_t v)
2462{
2463 char buf[BUF_SIZE];
2464 XMLUtil::ToStr(v, buf, BUF_SIZE);
2465 PushAttribute(name, buf);
2466}
2467
2468
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002469void XMLPrinter::PushAttribute( const char* name, bool v )
2470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002471 char buf[BUF_SIZE];
2472 XMLUtil::ToStr( v, buf, BUF_SIZE );
2473 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002474}
2475
2476
2477void XMLPrinter::PushAttribute( const char* name, double v )
2478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 char buf[BUF_SIZE];
2480 XMLUtil::ToStr( v, buf, BUF_SIZE );
2481 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002482}
2483
2484
Uli Kustererca412e82014-02-01 13:35:05 +01002485void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002486{
Lee Thomason624d43f2012-10-12 10:58:48 -07002487 --_depth;
2488 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002489
Lee Thomason624d43f2012-10-12 10:58:48 -07002490 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002491 Print( "/>" );
2492 }
2493 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002494 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002496 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002497 }
2498 Print( "</%s>", name );
2499 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002500
Lee Thomason624d43f2012-10-12 10:58:48 -07002501 if ( _textDepth == _depth ) {
2502 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 }
Uli Kustererca412e82014-02-01 13:35:05 +01002504 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002505 Print( "\n" );
2506 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002507 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002508}
2509
2510
Dmitry-Mea092bc12014-12-23 17:57:05 +03002511void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002512{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002513 if ( !_elementJustOpened ) {
2514 return;
2515 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002516 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002517 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002518}
2519
2520
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002521void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002522{
Lee Thomason624d43f2012-10-12 10:58:48 -07002523 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002524
Dmitry-Mea092bc12014-12-23 17:57:05 +03002525 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002526 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002527 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 }
2529 else {
2530 PrintString( text, true );
2531 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002532}
2533
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002534void XMLPrinter::PushText( int64_t value )
2535{
2536 char buf[BUF_SIZE];
2537 XMLUtil::ToStr( value, buf, BUF_SIZE );
2538 PushText( buf, false );
2539}
2540
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002541void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002543 char buf[BUF_SIZE];
2544 XMLUtil::ToStr( value, buf, BUF_SIZE );
2545 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002546}
2547
2548
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002549void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002550{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 char buf[BUF_SIZE];
2552 XMLUtil::ToStr( value, buf, BUF_SIZE );
2553 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002554}
2555
2556
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002557void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002559 char buf[BUF_SIZE];
2560 XMLUtil::ToStr( value, buf, BUF_SIZE );
2561 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002562}
2563
2564
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002565void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002567 char buf[BUF_SIZE];
2568 XMLUtil::ToStr( value, buf, BUF_SIZE );
2569 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002570}
2571
2572
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002573void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002575 char buf[BUF_SIZE];
2576 XMLUtil::ToStr( value, buf, BUF_SIZE );
2577 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002578}
2579
Lee Thomason5cae8972012-01-24 18:03:07 -08002580
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002581void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002582{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002583 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002584 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002585 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002586 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002587 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002588 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002589 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002590}
Lee Thomason751da522012-02-10 08:50:51 -08002591
2592
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002593void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002594{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002595 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002596 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002597 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002598 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002599 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002600 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002601 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002602}
2603
2604
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002605void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002606{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002607 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002608 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002610 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002612 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002614}
2615
2616
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002617bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002618{
Lee Thomason624d43f2012-10-12 10:58:48 -07002619 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002620 if ( doc.HasBOM() ) {
2621 PushHeader( true, false );
2622 }
2623 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002624}
2625
2626
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002627bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002628{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002629 const XMLElement* parentElem = 0;
2630 if ( element.Parent() ) {
2631 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002632 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002633 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002634 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002635 while ( attribute ) {
2636 PushAttribute( attribute->Name(), attribute->Value() );
2637 attribute = attribute->Next();
2638 }
2639 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002640}
2641
2642
Uli Kustererca412e82014-02-01 13:35:05 +01002643bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002644{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002645 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002646 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002647}
2648
2649
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002650bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 PushText( text.Value(), text.CData() );
2653 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002654}
2655
2656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002657bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002658{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002659 PushComment( comment.Value() );
2660 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002661}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002662
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002663bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002664{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 PushDeclaration( declaration.Value() );
2666 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002667}
2668
2669
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002670bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002671{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 PushUnknown( unknown.Value() );
2673 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002674}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002675
Lee Thomason685b8952012-11-12 13:00:06 -08002676} // namespace tinyxml2
2677