blob: a8a4a2069f9eb43f6bc2a79d789ce24d774aabc0 [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
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300427 // Scary scary fall throughs are annotated with carefully designed comments
428 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700429 switch (*length) {
430 case 4:
431 --output;
432 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
433 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300434 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 case 3:
436 --output;
437 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
438 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300439 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 case 2:
441 --output;
442 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
443 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300444 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 case 1:
446 --output;
447 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100448 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300449 default:
450 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800452}
453
454
455const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 // Presume an entity, and pull it out.
458 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( *(p+1) == '#' && *(p+2) ) {
461 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300462 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 ptrdiff_t delta = 0;
464 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800465 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *(p+2) == 'x' ) {
468 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300469 const char* q = p+3;
470 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 return 0;
472 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800473
Lee Thomason7e67bc82015-01-12 14:05:12 -0800474 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800475
Dmitry-Me9f56e122015-01-12 10:07:54 +0300476 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 return 0;
478 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800479 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800480
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 delta = q-p;
482 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800483
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700485 unsigned int digit = 0;
486
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300488 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 }
490 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300491 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 }
493 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300494 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 }
496 else {
497 return 0;
498 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100499 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300500 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
501 const unsigned int digitScaled = mult * digit;
502 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
503 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300504 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 mult *= 16;
506 --q;
507 }
508 }
509 else {
510 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300511 const char* q = p+2;
512 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 return 0;
514 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800515
Lee Thomason7e67bc82015-01-12 14:05:12 -0800516 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800517
Dmitry-Me9f56e122015-01-12 10:07:54 +0300518 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 return 0;
520 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800521 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 delta = q-p;
524 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 while ( *q != '#' ) {
527 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300528 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100529 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300530 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
531 const unsigned int digitScaled = mult * digit;
532 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
533 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 }
535 else {
536 return 0;
537 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300538 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 mult *= 10;
540 --q;
541 }
542 }
543 // convert the UCS to UTF-8
544 ConvertUTF32ToUTF8( ucs, value, length );
545 return p + delta + 1;
546 }
547 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800548}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549
550
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700551void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700554}
555
556
557void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700560}
561
562
563void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
564{
Lee Thomasonce667c92016-12-26 16:45:30 -0800565 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700566}
567
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800568/*
569 ToStr() of a number is a very tricky topic.
570 https://github.com/leethomason/tinyxml2/issues/106
571*/
Lee Thomason21be8822012-07-15 17:27:22 -0700572void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
573{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800574 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700575}
576
577
578void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
579{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800580 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583
Lee Thomason51c12712016-06-04 20:18:49 -0700584void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
585{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700586 // horrible syntax trick to make the compiler happy about %lld
587 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700588}
589
590
Lee Thomason21be8822012-07-15 17:27:22 -0700591bool XMLUtil::ToInt( const char* str, int* value )
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
594 return true;
595 }
596 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700597}
598
599bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
602 return true;
603 }
604 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700605}
606
607bool XMLUtil::ToBool( const char* str, bool* value )
608{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 int ival = 0;
610 if ( ToInt( str, &ival )) {
611 *value = (ival==0) ? false : true;
612 return true;
613 }
614 if ( StringEqual( str, "true" ) ) {
615 *value = true;
616 return true;
617 }
618 else if ( StringEqual( str, "false" ) ) {
619 *value = false;
620 return true;
621 }
622 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700623}
624
625
626bool XMLUtil::ToFloat( const char* str, float* value )
627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
629 return true;
630 }
631 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700632}
633
Lee Thomason51c12712016-06-04 20:18:49 -0700634
Lee Thomason21be8822012-07-15 17:27:22 -0700635bool XMLUtil::ToDouble( const char* str, double* value )
636{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
638 return true;
639 }
640 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700641}
642
643
Lee Thomason51c12712016-06-04 20:18:49 -0700644bool XMLUtil::ToInt64(const char* str, int64_t* value)
645{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700646 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
647 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
648 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700649 return true;
650 }
651 return false;
652}
653
654
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700655char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656{
Dmitry-Me02384662015-03-03 16:02:13 +0300657 TIXMLASSERT( node );
658 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400659 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000660 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000661 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300662 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300663 *node = 0;
664 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 return p;
666 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Dmitry-Me962083b2015-05-26 11:38:30 +0300668 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* xmlHeader = { "<?" };
670 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300672 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int xmlHeaderLen = 2;
676 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300678 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400683 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300685 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000686 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += xmlHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300690 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000691 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 p += commentHeaderLen;
693 }
694 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300695 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000697 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 p += cdataHeaderLen;
699 text->SetCData( true );
700 }
701 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300702 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000703 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 p += dtdHeaderLen;
705 }
706 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300707 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p += elementHeaderLen;
710 }
711 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300712 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000713 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000715 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717
Dmitry-Me02384662015-03-03 16:02:13 +0300718 TIXMLASSERT( returnNode );
719 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 *node = returnNode;
721 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722}
723
724
Lee Thomason751da522012-02-10 08:50:51 -0800725bool XMLDocument::Accept( XMLVisitor* visitor ) const
726{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300727 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 if ( visitor->VisitEnter( *this ) ) {
729 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
730 if ( !node->Accept( visitor ) ) {
731 break;
732 }
733 }
734 }
735 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800736}
Lee Thomason56bdd022012-02-09 18:16:58 -0800737
738
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800739// --------- XMLNode ----------- //
740
741XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 _document( doc ),
743 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000744 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200746 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700747 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200748 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800749{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750}
751
752
753XMLNode::~XMLNode()
754{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 if ( _parent ) {
757 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800759}
760
Michael Daumling21626882013-10-22 17:03:37 +0200761const char* XMLNode::Value() const
762{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300763 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530764 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530765 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200766 return _value.GetStr();
767}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800768
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800769void XMLNode::SetValue( const char* str, bool staticMem )
770{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700772 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 }
774 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800777}
778
Dmitry-Me3f63f212017-06-19 18:25:19 +0300779XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700780{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300781 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700782 if (!clone) return 0;
783
784 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300785 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700786 TIXMLASSERT(childClone);
787 clone->InsertEndChild(childClone);
788 }
789 return clone;
790}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800791
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800793{
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300795 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300796 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800799}
800
801
802void XMLNode::Unlink( XMLNode* child )
803{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300804 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300805 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300806 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 if ( child == _firstChild ) {
808 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( child == _lastChild ) {
811 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 }
Lee Thomasond923c672012-01-23 08:44:25 -0800813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( child->_prev ) {
815 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 if ( child->_next ) {
818 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
Lee Thomason8a763612017-06-16 09:30:16 -0700820 child->_next = 0;
821 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700822 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823}
824
825
U-Stream\Leeae25a442012-02-17 17:48:16 -0800826void XMLNode::DeleteChild( XMLNode* node )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100831 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700832 TIXMLASSERT(node->_prev == 0);
833 TIXMLASSERT(node->_next == 0);
834 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400835 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800836}
837
838
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800839XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
840{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300841 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300842 if ( addThis->_document != _document ) {
843 TIXMLASSERT( false );
844 return 0;
845 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800846 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 if ( _lastChild ) {
849 TIXMLASSERT( _firstChild );
850 TIXMLASSERT( _lastChild->_next == 0 );
851 _lastChild->_next = addThis;
852 addThis->_prev = _lastChild;
853 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800854
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 }
857 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 TIXMLASSERT( _firstChild == 0 );
859 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_prev = 0;
862 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700864 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800866}
867
868
Lee Thomason1ff38e02012-02-14 18:18:16 -0800869XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
870{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300871 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300872 if ( addThis->_document != _document ) {
873 TIXMLASSERT( false );
874 return 0;
875 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800876 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 if ( _firstChild ) {
879 TIXMLASSERT( _lastChild );
880 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 _firstChild->_prev = addThis;
883 addThis->_next = _firstChild;
884 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800885
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 TIXMLASSERT( _lastChild == 0 );
890 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800891
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 addThis->_prev = 0;
893 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400896 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800897}
898
899
900XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
901{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300902 TIXMLASSERT( addThis );
903 if ( addThis->_document != _document ) {
904 TIXMLASSERT( false );
905 return 0;
906 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700907
Dmitry-Meabb2d042014-12-09 12:59:31 +0300908 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700909
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300911 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 return 0;
913 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800914
Lee Thomason624d43f2012-10-12 10:58:48 -0700915 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 // The last node or the only node.
917 return InsertEndChild( addThis );
918 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800919 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700920 addThis->_prev = afterThis;
921 addThis->_next = afterThis->_next;
922 afterThis->_next->_prev = addThis;
923 afterThis->_next = addThis;
924 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800926}
927
928
929
930
Dmitry-Me886ad972015-07-22 11:00:51 +0300931const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800932{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300933 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300934 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 }
938 }
939 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800940}
941
942
Dmitry-Me886ad972015-07-22 11:00:51 +0300943const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800944{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300945 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300946 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300948 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 }
950 }
951 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800952}
953
954
Dmitry-Me886ad972015-07-22 11:00:51 +0300955const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300957 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300958 const XMLElement* element = node->ToElementWithName( name );
959 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400960 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 }
962 }
963 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964}
965
966
Dmitry-Me886ad972015-07-22 11:00:51 +0300967const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800968{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300969 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300970 const XMLElement* element = node->ToElementWithName( name );
971 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400972 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 }
974 }
975 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976}
977
978
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300979char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 // This is a recursive method, but thinking about it "at the current level"
982 // it is a pretty simple flat list:
983 // <foo/>
984 // <!-- comment -->
985 //
986 // With a special case:
987 // <foo>
988 // </foo>
989 // <!-- comment -->
990 //
991 // Where the closing element (/foo) *must* be the next thing after the opening
992 // element, and the names must match. BUT the tricky bit is that the closing
993 // element will be read by the child.
994 //
995 // 'endTag' is the end tag for this node, it is returned by a call to a child.
996 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 while( p && *p ) {
999 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001000
Lee Thomason624d43f2012-10-12 10:58:48 -07001001 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001002 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001003 if ( node == 0 ) {
1004 break;
1005 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006
kezenatore3531812016-11-29 19:49:07 +10001007 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001008
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001010 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001012 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001013 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001014 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 }
1016 break;
1017 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001018
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301019 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301020 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001021 // Declarations are only allowed at document level
1022 bool wellLocated = ( ToDocument() != 0 );
1023 if ( wellLocated ) {
1024 // Multiple declarations are allowed but all declarations
1025 // must occur before anything else
1026 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1027 if ( !existingNode->ToDeclaration() ) {
1028 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301029 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001030 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301031 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001032 }
1033 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001034 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001035 DeleteNode( node );
1036 break;
1037 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301038 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301039
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001040 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001042 // We read the end tag. Return it to the parent.
1043 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001044 if ( parentEndTag ) {
1045 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001046 }
1047 node->_memPool->SetTracked(); // created and then immediately deleted.
1048 DeleteNode( node );
1049 return p;
1050 }
1051
1052 // Handle an end tag returned to this level.
1053 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001054 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001055 if ( endTag.Empty() ) {
1056 if ( ele->ClosingType() == XMLElement::OPEN ) {
1057 mismatch = true;
1058 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001060 else {
1061 if ( ele->ClosingType() != XMLElement::OPEN ) {
1062 mismatch = true;
1063 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001064 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001065 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001068 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001069 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001070 DeleteNode( node );
1071 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001072 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 }
JayXondbfdd8f2014-12-12 20:07:14 -05001074 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 }
1076 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001077}
1078
Lee Thomason816d3fa2017-06-05 14:35:55 -07001079/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001080{
1081 if ( node == 0 ) {
1082 return;
1083 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001084 TIXMLASSERT(node->_document);
1085 if (!node->ToDocument()) {
1086 node->_document->MarkInUse(node);
1087 }
1088
Dmitry-Mee3225b12014-09-03 11:03:11 +04001089 MemPool* pool = node->_memPool;
1090 node->~XMLNode();
1091 pool->Free( node );
1092}
1093
Lee Thomason3cebdc42015-01-05 17:16:28 -08001094void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001095{
1096 TIXMLASSERT( insertThis );
1097 TIXMLASSERT( insertThis->_document == _document );
1098
Lee Thomason816d3fa2017-06-05 14:35:55 -07001099 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001100 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001101 }
1102 else {
1103 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001104 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001105 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001106}
1107
Dmitry-Meecb9b072016-10-12 16:44:59 +03001108const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1109{
1110 const XMLElement* element = this->ToElement();
1111 if ( element == 0 ) {
1112 return 0;
1113 }
1114 if ( name == 0 ) {
1115 return element;
1116 }
1117 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1118 return element;
1119 }
1120 return 0;
1121}
1122
Lee Thomason5492a1c2012-01-23 15:32:10 -08001123// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001124char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 const char* start = p;
1127 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001128 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001130 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 }
1132 return p;
1133 }
1134 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1136 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001137 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001139
kezenator4f756162016-11-29 19:46:27 +10001140 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( p && *p ) {
1142 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001143 }
1144 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001145 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
1147 }
1148 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001149}
1150
1151
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001152XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 }
1157 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1158 text->SetCData( this->CData() );
1159 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160}
1161
1162
1163bool XMLText::ShallowEqual( const XMLNode* compare ) const
1164{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001165 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001166 const XMLText* text = compare->ToText();
1167 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
Lee Thomason56bdd022012-02-09 18:16:58 -08001171bool XMLText::Accept( XMLVisitor* visitor ) const
1172{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001173 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001175}
1176
1177
Lee Thomason3f57d272012-01-11 15:30:03 -08001178// --------- XMLComment ---------- //
1179
Lee Thomasone4422302012-01-20 17:59:50 -08001180XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001181{
1182}
1183
1184
Lee Thomasonce0763e2012-01-11 15:43:54 -08001185XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001186{
Lee Thomason3f57d272012-01-11 15:30:03 -08001187}
1188
1189
kezenator4f756162016-11-29 19:46:27 +10001190char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 // Comment parses as text.
1193 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001194 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001196 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 }
1198 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001199}
1200
1201
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001202XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 }
1207 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1208 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001209}
1210
1211
1212bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1213{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001214 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001215 const XMLComment* comment = compare->ToComment();
1216 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217}
1218
1219
Lee Thomason751da522012-02-10 08:50:51 -08001220bool XMLComment::Accept( XMLVisitor* visitor ) const
1221{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001222 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001224}
Lee Thomason56bdd022012-02-09 18:16:58 -08001225
1226
Lee Thomason50f97b22012-02-11 16:33:40 -08001227// --------- XMLDeclaration ---------- //
1228
1229XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1230{
1231}
1232
1233
1234XMLDeclaration::~XMLDeclaration()
1235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001237}
1238
1239
kezenator4f756162016-11-29 19:46:27 +10001240char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 // Declaration parses as text.
1243 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001244 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001246 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 }
1248 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001249}
1250
1251
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1253{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 }
1257 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1258 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001259}
1260
1261
1262bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1263{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001264 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001265 const XMLDeclaration* declaration = compare->ToDeclaration();
1266 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001267}
1268
1269
1270
Lee Thomason50f97b22012-02-11 16:33:40 -08001271bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1272{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001273 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001275}
1276
1277// --------- XMLUnknown ---------- //
1278
1279XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1280{
1281}
1282
1283
1284XMLUnknown::~XMLUnknown()
1285{
1286}
1287
1288
kezenator4f756162016-11-29 19:46:27 +10001289char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 // Unknown parses as text.
1292 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001293
kezenator4f756162016-11-29 19:46:27 +10001294 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001296 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 }
1298 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001299}
1300
1301
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001302XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001305 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 }
1307 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1308 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001309}
1310
1311
1312bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1313{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001314 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001315 const XMLUnknown* unknown = compare->ToUnknown();
1316 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001317}
1318
1319
Lee Thomason50f97b22012-02-11 16:33:40 -08001320bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1321{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001322 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001324}
1325
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001326// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001327
1328const char* XMLAttribute::Name() const
1329{
1330 return _name.GetStr();
1331}
1332
1333const char* XMLAttribute::Value() const
1334{
1335 return _value.GetStr();
1336}
1337
kezenator4f756162016-11-29 19:46:27 +10001338char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001341 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( !p || !*p ) {
1343 return 0;
1344 }
Lee Thomason22aead12012-01-23 13:29:35 -08001345
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001347 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001348 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 return 0;
1350 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001351
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001353 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( *p != '\"' && *p != '\'' ) {
1355 return 0;
1356 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001357
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 char endTag[2] = { *p, 0 };
1359 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001360
kezenator4f756162016-11-29 19:46:27 +10001361 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001363}
1364
1365
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001366void XMLAttribute::SetName( const char* n )
1367{
Lee Thomason624d43f2012-10-12 10:58:48 -07001368 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001369}
1370
1371
Lee Thomason2fa81722012-11-09 12:37:46 -08001372XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001373{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001375 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 }
1377 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001378}
1379
1380
Lee Thomason2fa81722012-11-09 12:37:46 -08001381XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001384 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 }
1386 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001387}
1388
1389
Lee Thomason51c12712016-06-04 20:18:49 -07001390XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1391{
1392 if (XMLUtil::ToInt64(Value(), value)) {
1393 return XML_SUCCESS;
1394 }
1395 return XML_WRONG_ATTRIBUTE_TYPE;
1396}
1397
1398
Lee Thomason2fa81722012-11-09 12:37:46 -08001399XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001402 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001405}
1406
1407
Lee Thomason2fa81722012-11-09 12:37:46 -08001408XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001411 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 }
1413 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001414}
1415
1416
Lee Thomason2fa81722012-11-09 12:37:46 -08001417XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001420 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
1422 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001423}
1424
1425
1426void XMLAttribute::SetAttribute( const char* v )
1427{
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001429}
1430
1431
Lee Thomason1ff38e02012-02-14 18:18:16 -08001432void XMLAttribute::SetAttribute( int v )
1433{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 char buf[BUF_SIZE];
1435 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438
1439
1440void XMLAttribute::SetAttribute( unsigned v )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001445}
1446
1447
Lee Thomason51c12712016-06-04 20:18:49 -07001448void XMLAttribute::SetAttribute(int64_t v)
1449{
1450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr(v, buf, BUF_SIZE);
1452 _value.SetStr(buf);
1453}
1454
1455
1456
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001457void XMLAttribute::SetAttribute( bool v )
1458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 char buf[BUF_SIZE];
1460 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001462}
1463
1464void XMLAttribute::SetAttribute( double v )
1465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 char buf[BUF_SIZE];
1467 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001469}
1470
1471void XMLAttribute::SetAttribute( float v )
1472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 char buf[BUF_SIZE];
1474 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001476}
1477
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001478
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001479// --------- XMLElement ---------- //
1480XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001481 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483{
1484}
1485
1486
1487XMLElement::~XMLElement()
1488{
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 while( _rootAttribute ) {
1490 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001491 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001494}
1495
1496
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001497const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1498{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001499 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1501 return a;
1502 }
1503 }
1504 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505}
1506
1507
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001508const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001509{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 const XMLAttribute* a = FindAttribute( name );
1511 if ( !a ) {
1512 return 0;
1513 }
1514 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1515 return a->Value();
1516 }
1517 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001518}
1519
Josh Wittnercf3dd092016-10-11 18:57:17 -07001520int XMLElement::IntAttribute(const char* name, int defaultValue) const
1521{
1522 int i = defaultValue;
1523 QueryIntAttribute(name, &i);
1524 return i;
1525}
1526
1527unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1528{
1529 unsigned i = defaultValue;
1530 QueryUnsignedAttribute(name, &i);
1531 return i;
1532}
1533
1534int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1535{
1536 int64_t i = defaultValue;
1537 QueryInt64Attribute(name, &i);
1538 return i;
1539}
1540
1541bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1542{
1543 bool b = defaultValue;
1544 QueryBoolAttribute(name, &b);
1545 return b;
1546}
1547
1548double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1549{
1550 double d = defaultValue;
1551 QueryDoubleAttribute(name, &d);
1552 return d;
1553}
1554
1555float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1556{
1557 float f = defaultValue;
1558 QueryFloatAttribute(name, &f);
1559 return f;
1560}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001561
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001562const char* XMLElement::GetText() const
1563{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001565 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 }
1567 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001568}
1569
1570
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001571void XMLElement::SetText( const char* inText )
1572{
Uli Kusterer869bb592014-01-21 01:36:16 +01001573 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001574 FirstChild()->SetValue( inText );
1575 else {
1576 XMLText* theText = GetDocument()->NewText( inText );
1577 InsertFirstChild( theText );
1578 }
1579}
1580
Lee Thomason5bb2d802014-01-24 10:42:57 -08001581
1582void XMLElement::SetText( int v )
1583{
1584 char buf[BUF_SIZE];
1585 XMLUtil::ToStr( v, buf, BUF_SIZE );
1586 SetText( buf );
1587}
1588
1589
1590void XMLElement::SetText( unsigned v )
1591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
Lee Thomason51c12712016-06-04 20:18:49 -07001598void XMLElement::SetText(int64_t v)
1599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr(v, buf, BUF_SIZE);
1602 SetText(buf);
1603}
1604
1605
1606void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr( v, buf, BUF_SIZE );
1610 SetText( buf );
1611}
1612
1613
1614void XMLElement::SetText( float v )
1615{
1616 char buf[BUF_SIZE];
1617 XMLUtil::ToStr( v, buf, BUF_SIZE );
1618 SetText( buf );
1619}
1620
1621
1622void XMLElement::SetText( double v )
1623{
1624 char buf[BUF_SIZE];
1625 XMLUtil::ToStr( v, buf, BUF_SIZE );
1626 SetText( buf );
1627}
1628
1629
MortenMacFly4ee49f12013-01-14 20:03:14 +01001630XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001631{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001633 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001634 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 return XML_SUCCESS;
1636 }
1637 return XML_CAN_NOT_CONVERT_TEXT;
1638 }
1639 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001640}
1641
1642
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001644{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001646 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001647 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001648 return XML_SUCCESS;
1649 }
1650 return XML_CAN_NOT_CONVERT_TEXT;
1651 }
1652 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001653}
1654
1655
Lee Thomason51c12712016-06-04 20:18:49 -07001656XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1657{
1658 if (FirstChild() && FirstChild()->ToText()) {
1659 const char* t = FirstChild()->Value();
1660 if (XMLUtil::ToInt64(t, ival)) {
1661 return XML_SUCCESS;
1662 }
1663 return XML_CAN_NOT_CONVERT_TEXT;
1664 }
1665 return XML_NO_TEXT_NODE;
1666}
1667
1668
MortenMacFly4ee49f12013-01-14 20:03:14 +01001669XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001670{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001672 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001673 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 return XML_SUCCESS;
1675 }
1676 return XML_CAN_NOT_CONVERT_TEXT;
1677 }
1678 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001679}
1680
1681
MortenMacFly4ee49f12013-01-14 20:03:14 +01001682XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001683{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001685 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001686 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 return XML_SUCCESS;
1688 }
1689 return XML_CAN_NOT_CONVERT_TEXT;
1690 }
1691 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001692}
1693
1694
MortenMacFly4ee49f12013-01-14 20:03:14 +01001695XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001696{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001698 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001699 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 return XML_SUCCESS;
1701 }
1702 return XML_CAN_NOT_CONVERT_TEXT;
1703 }
1704 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001705}
1706
Josh Wittnercf3dd092016-10-11 18:57:17 -07001707int XMLElement::IntText(int defaultValue) const
1708{
1709 int i = defaultValue;
1710 QueryIntText(&i);
1711 return i;
1712}
1713
1714unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1715{
1716 unsigned i = defaultValue;
1717 QueryUnsignedText(&i);
1718 return i;
1719}
1720
1721int64_t XMLElement::Int64Text(int64_t defaultValue) const
1722{
1723 int64_t i = defaultValue;
1724 QueryInt64Text(&i);
1725 return i;
1726}
1727
1728bool XMLElement::BoolText(bool defaultValue) const
1729{
1730 bool b = defaultValue;
1731 QueryBoolText(&b);
1732 return b;
1733}
1734
1735double XMLElement::DoubleText(double defaultValue) const
1736{
1737 double d = defaultValue;
1738 QueryDoubleText(&d);
1739 return d;
1740}
1741
1742float XMLElement::FloatText(float defaultValue) const
1743{
1744 float f = defaultValue;
1745 QueryFloatText(&f);
1746 return f;
1747}
Lee Thomason21be8822012-07-15 17:27:22 -07001748
1749
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001750XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 XMLAttribute* last = 0;
1753 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1758 break;
1759 }
1760 }
1761 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001762 attrib = CreateAttribute();
1763 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001765 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001769 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 }
1772 attrib->SetName( name );
1773 }
1774 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001775}
1776
1777
U-Stream\Leeae25a442012-02-17 17:48:16 -08001778void XMLElement::DeleteAttribute( const char* name )
1779{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1783 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
1786 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001789 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 break;
1791 }
1792 prev = a;
1793 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001794}
1795
1796
kezenator4f756162016-11-29 19:46:27 +10001797char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001798{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 const char* start = p;
1800 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001801
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 // Read the attributes.
1803 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001804 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001805 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001806 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 return 0;
1808 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001809
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001811 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001812 XMLAttribute* attrib = CreateAttribute();
1813 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001814 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001815
kezenatorec694152016-11-26 17:21:43 +10001816 int attrLineNum = attrib->_parseLineNum;
1817
kezenator4f756162016-11-29 19:46:27 +10001818 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001820 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001821 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 return 0;
1823 }
1824 // There is a minor bug here: if the attribute in the source xml
1825 // document is duplicated, it will not be detected and the
1826 // attribute will be doubly added. However, tracking the 'prevAttribute'
1827 // avoids re-scanning the attribute list. Preferring performance for
1828 // now, may reconsider in the future.
1829 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001830 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
1833 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001834 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
1837 prevAttribute = attrib;
1838 }
1839 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 else if ( *p == '>' ) {
1841 ++p;
1842 break;
1843 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001844 // end of the tag
1845 else if ( *p == '/' && *(p+1) == '>' ) {
1846 _closingType = CLOSED;
1847 return p+2; // done; sealed element.
1848 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 else {
kezenatorec694152016-11-26 17:21:43 +10001850 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 return 0;
1852 }
1853 }
1854 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001855}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001856
Dmitry-Mee3225b12014-09-03 11:03:11 +04001857void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1858{
1859 if ( attribute == 0 ) {
1860 return;
1861 }
1862 MemPool* pool = attribute->_memPool;
1863 attribute->~XMLAttribute();
1864 pool->Free( attribute );
1865}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001866
Dmitry-Mea60caa22016-11-22 18:28:08 +03001867XMLAttribute* XMLElement::CreateAttribute()
1868{
1869 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1870 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001871 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001872 attrib->_memPool = &_document->_attributePool;
1873 attrib->_memPool->SetTracked();
1874 return attrib;
1875}
1876
Lee Thomason67d61312012-01-24 16:01:51 -08001877//
1878// <ele></ele>
1879// <ele>foo<b>bar</b></ele>
1880//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001881char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001882{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001884 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001885
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 // The closing element is the </element> form. It is
1887 // parsed just like a regular element then deleted from
1888 // the DOM.
1889 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 ++p;
1892 }
Lee Thomason67d61312012-01-24 16:01:51 -08001893
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 p = _value.ParseName( p );
1895 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 return 0;
1897 }
Lee Thomason67d61312012-01-24 16:01:51 -08001898
kezenator4f756162016-11-29 19:46:27 +10001899 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001900 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 return p;
1902 }
Lee Thomason67d61312012-01-24 16:01:51 -08001903
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001904 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001906}
1907
1908
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001909
1910XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 }
1915 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1916 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1917 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1918 }
1919 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001920}
1921
1922
1923bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1924{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001925 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001927 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 const XMLAttribute* a=FirstAttribute();
1930 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001931
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 while ( a && b ) {
1933 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1934 return false;
1935 }
1936 a = a->Next();
1937 b = b->Next();
1938 }
1939 if ( a || b ) {
1940 // different count
1941 return false;
1942 }
1943 return true;
1944 }
1945 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001946}
1947
1948
Lee Thomason751da522012-02-10 08:50:51 -08001949bool XMLElement::Accept( XMLVisitor* visitor ) const
1950{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001951 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1954 if ( !node->Accept( visitor ) ) {
1955 break;
1956 }
1957 }
1958 }
1959 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001960}
Lee Thomason56bdd022012-02-09 18:16:58 -08001961
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001962
Lee Thomason3f57d272012-01-11 15:30:03 -08001963// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001964
1965// Warning: List must match 'enum XMLError'
1966const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1967 "XML_SUCCESS",
1968 "XML_NO_ATTRIBUTE",
1969 "XML_WRONG_ATTRIBUTE_TYPE",
1970 "XML_ERROR_FILE_NOT_FOUND",
1971 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1972 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001973 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001974 "XML_ERROR_PARSING_ELEMENT",
1975 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001976 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001977 "XML_ERROR_PARSING_TEXT",
1978 "XML_ERROR_PARSING_CDATA",
1979 "XML_ERROR_PARSING_COMMENT",
1980 "XML_ERROR_PARSING_DECLARATION",
1981 "XML_ERROR_PARSING_UNKNOWN",
1982 "XML_ERROR_EMPTY_DOCUMENT",
1983 "XML_ERROR_MISMATCHED_ELEMENT",
1984 "XML_ERROR_PARSING",
1985 "XML_CAN_NOT_CONVERT_TEXT",
1986 "XML_NO_TEXT_NODE"
1987};
1988
1989
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001990XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001991 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001992 _writeBOM( false ),
1993 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001994 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001995 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001996 _errorLineNum( 0 ),
1997 _charBuffer( 0 ),
1998 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001999{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002000 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2001 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002002}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002003
2004
Lee Thomason3f57d272012-01-11 15:30:03 -08002005XMLDocument::~XMLDocument()
2006{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002007 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002008}
2009
2010
Lee Thomason816d3fa2017-06-05 14:35:55 -07002011void XMLDocument::MarkInUse(XMLNode* node)
2012{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002013 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002014 TIXMLASSERT(node->_parent == 0);
2015
2016 for (int i = 0; i < _unlinked.Size(); ++i) {
2017 if (node == _unlinked[i]) {
2018 _unlinked.SwapRemove(i);
2019 break;
2020 }
2021 }
2022}
2023
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002024void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002025{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002026 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002027 while( _unlinked.Size()) {
2028 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2029 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002030
Dmitry-Meab37df82014-11-28 12:08:36 +03002031#ifdef DEBUG
2032 const bool hadError = Error();
2033#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002034 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002035
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 delete [] _charBuffer;
2037 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002038
2039#if 0
2040 _textPool.Trace( "text" );
2041 _elementPool.Trace( "element" );
2042 _commentPool.Trace( "comment" );
2043 _attributePool.Trace( "attribute" );
2044#endif
2045
2046#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002047 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002048 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2049 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2050 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2051 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2052 }
2053#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002054}
2055
Lee Thomason3f57d272012-01-11 15:30:03 -08002056
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002057void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002058{
2059 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002060 if (target == this) {
2061 return; // technically success - a no-op.
2062 }
Lee Thomason7085f002017-06-01 18:09:43 -07002063
2064 target->Clear();
2065 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2066 target->InsertEndChild(node->DeepClone(target));
2067 }
2068}
2069
Lee Thomason2c85a712012-01-31 08:24:24 -08002070XMLElement* XMLDocument::NewElement( const char* name )
2071{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002072 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 ele->SetName( name );
2074 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002075}
2076
2077
Lee Thomason1ff38e02012-02-14 18:18:16 -08002078XMLComment* XMLDocument::NewComment( const char* str )
2079{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002080 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 comment->SetValue( str );
2082 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002083}
2084
2085
2086XMLText* XMLDocument::NewText( const char* str )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 text->SetValue( str );
2090 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002091}
2092
2093
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002094XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2098 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002099}
2100
2101
2102XMLUnknown* XMLDocument::NewUnknown( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 unk->SetValue( str );
2106 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
Dmitry-Me01578db2014-08-19 10:18:48 +04002109static FILE* callfopen( const char* filepath, const char* mode )
2110{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002111 TIXMLASSERT( filepath );
2112 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002113#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2114 FILE* fp = 0;
2115 errno_t err = fopen_s( &fp, filepath, mode );
2116 if ( err ) {
2117 return 0;
2118 }
2119#else
2120 FILE* fp = fopen( filepath, mode );
2121#endif
2122 return fp;
2123}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002124
2125void XMLDocument::DeleteNode( XMLNode* node ) {
2126 TIXMLASSERT( node );
2127 TIXMLASSERT(node->_document == this );
2128 if (node->_parent) {
2129 node->_parent->DeleteChild( node );
2130 }
2131 else {
2132 // Isn't in the tree.
2133 // Use the parent delete.
2134 // Also, we need to mark it tracked: we 'know'
2135 // it was never used.
2136 node->_memPool->SetTracked();
2137 // Call the static XMLNode version:
2138 XMLNode::DeleteNode(node);
2139 }
2140}
2141
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002142
Lee Thomason2fa81722012-11-09 12:37:46 -08002143XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002144{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002145 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002146 FILE* fp = callfopen( filename, "rb" );
2147 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002148 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
2151 LoadFile( fp );
2152 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002154}
2155
Dmitry-Me901fed52015-09-25 10:29:51 +03002156// This is likely overengineered template art to have a check that unsigned long value incremented
2157// by one still fits into size_t. If size_t type is larger than unsigned long type
2158// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2159// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2160// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2161// types sizes relate to each other.
2162template
2163<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2164struct LongFitsIntoSizeTMinusOne {
2165 static bool Fits( unsigned long value )
2166 {
2167 return value < (size_t)-1;
2168 }
2169};
2170
2171template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002172struct LongFitsIntoSizeTMinusOne<false> {
2173 static bool Fits( unsigned long )
2174 {
2175 return true;
2176 }
2177};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002178
Lee Thomason2fa81722012-11-09 12:37:46 -08002179XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002180{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002181 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002182
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002183 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002184 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002185 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002186 return _errorID;
2187 }
2188
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002190 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002192 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002193 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002194 return _errorID;
2195 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002196 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002197
Dmitry-Me901fed52015-09-25 10:29:51 +03002198 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002199 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002200 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002201 return _errorID;
2202 }
2203
Dmitry-Me72801b82015-05-07 09:41:39 +03002204 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002205 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002206 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002208
Dmitry-Me72801b82015-05-07 09:41:39 +03002209 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002210 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 _charBuffer = new char[size+1];
2212 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002214 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002217
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002219
Dmitry-Me97476b72015-01-01 16:15:57 +03002220 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002222}
2223
2224
Lee Thomason2fa81722012-11-09 12:37:46 -08002225XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002226{
Dmitry-Me01578db2014-08-19 10:18:48 +04002227 FILE* fp = callfopen( filename, "w" );
2228 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002229 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
2232 SaveFile(fp, compact);
2233 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002235}
2236
2237
Lee Thomason2fa81722012-11-09 12:37:46 -08002238XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002239{
Ant Mitchell189198f2015-03-24 16:20:36 +00002240 // Clear any error from the last save, otherwise it will get reported
2241 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002242 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 XMLPrinter stream( fp, compact );
2244 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246}
2247
Lee Thomason1ff38e02012-02-14 18:18:16 -08002248
Lee Thomason2fa81722012-11-09 12:37:46 -08002249XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002250{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002251 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002252
Lee Thomason82d32002014-02-21 22:47:18 -08002253 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002254 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
2257 if ( len == (size_t)(-1) ) {
2258 len = strlen( p );
2259 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002260 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 _charBuffer = new char[ len+1 ];
2262 memcpy( _charBuffer, p, len );
2263 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002264
Dmitry-Me97476b72015-01-01 16:15:57 +03002265 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002266 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002267 // clean up now essentially dangling memory.
2268 // and the parse fail can put objects in the
2269 // pools that are dead and inaccessible.
2270 DeleteChildren();
2271 _elementPool.Clear();
2272 _attributePool.Clear();
2273 _textPool.Clear();
2274 _commentPool.Clear();
2275 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002276 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002277}
2278
2279
PKEuS1c5f99e2013-07-06 11:28:39 +02002280void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002281{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002282 if ( streamer ) {
2283 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002285 else {
2286 XMLPrinter stdoutStreamer( stdout );
2287 Accept( &stdoutStreamer );
2288 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002289}
2290
2291
kezenatorec694152016-11-26 17:21:43 +10002292void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002293{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002294 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002296
2297 _errorStr1.Reset();
2298 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002299 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002300
2301 if (str1)
2302 _errorStr1.SetStr(str1);
2303 if (str2)
2304 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002305}
2306
Lee Thomasone90e9012016-12-24 07:34:39 -08002307/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002308{
kezenator5a700712016-11-26 13:54:42 +10002309 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2310 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002311 TIXMLASSERT( errorName && errorName[0] );
2312 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002313}
Lee Thomason5cae8972012-01-24 18:03:07 -08002314
Lee Thomason8c9e3132017-06-26 16:55:01 -07002315const char* XMLDocument::GetErrorStr1() const
2316{
2317 return _errorStr1.GetStr();
2318}
2319
2320const char* XMLDocument::GetErrorStr2() const
2321{
2322 return _errorStr2.GetStr();
2323}
2324
kezenator5a700712016-11-26 13:54:42 +10002325const char* XMLDocument::ErrorName() const
2326{
Lee Thomasone90e9012016-12-24 07:34:39 -08002327 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002328}
2329
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002330void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002331{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002332 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 static const int LEN = 20;
2334 char buf1[LEN] = { 0 };
2335 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002336
Lee Thomason584af572016-09-05 14:14:16 -07002337 if ( !_errorStr1.Empty() ) {
2338 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 }
Lee Thomason584af572016-09-05 14:14:16 -07002340 if ( !_errorStr2.Empty() ) {
2341 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002343
Dmitry-Me2ad43202015-04-16 12:18:58 +03002344 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2345 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2346 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002347 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2348 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002350}
2351
Dmitry-Me97476b72015-01-01 16:15:57 +03002352void XMLDocument::Parse()
2353{
2354 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2355 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002356 _parseCurLineNum = 1;
2357 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002358 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002359 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002360 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002361 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002362 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002363 return;
2364 }
kezenator4f756162016-11-29 19:46:27 +10002365 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002366}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002367
PKEuS1bfb9542013-08-04 13:51:17 +02002368XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 _elementJustOpened( false ),
2370 _firstElement( true ),
2371 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002372 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 _textDepth( -1 ),
2374 _processEntities( true ),
2375 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002376{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 _entityFlag[i] = false;
2379 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002380 }
2381 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002382 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002383 const unsigned char flagIndex = (unsigned char)entityValue;
2384 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2385 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002387 _restrictedEntityFlag[(unsigned char)'&'] = true;
2388 _restrictedEntityFlag[(unsigned char)'<'] = true;
2389 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002390 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002391}
2392
2393
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002394void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002395{
2396 va_list va;
2397 va_start( va, format );
2398
Lee Thomason624d43f2012-10-12 10:58:48 -07002399 if ( _fp ) {
2400 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002401 }
2402 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002403 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 // Close out and re-start the va-args
2405 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002406 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002408 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002409 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002410 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002412 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002413}
2414
2415
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002416void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 for( int i=0; i<depth; ++i ) {
2419 Print( " " );
2420 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002421}
2422
2423
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002424void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002426 // Look for runs of bytes between entities to print.
2427 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002428
Lee Thomason624d43f2012-10-12 10:58:48 -07002429 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002430 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002432 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 // Remember, char is sometimes signed. (How many times has that bitten me?)
2434 if ( *q > 0 && *q < ENTITY_RANGE ) {
2435 // Check for entities. If one is found, flush
2436 // the stream up until the entity, write the
2437 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002438 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002440 const size_t delta = q - p;
2441 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002442 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002443 Print( "%.*s", toPrint, p );
2444 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002446 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 for( int i=0; i<NUM_ENTITIES; ++i ) {
2448 if ( entities[i].value == *q ) {
2449 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002450 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 break;
2452 }
2453 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002454 if ( !entityPatternPrinted ) {
2455 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2456 TIXMLASSERT( false );
2457 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 ++p;
2459 }
2460 }
2461 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002462 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002463 }
2464 }
2465 // Flush the remaining string. This will be the entire
2466 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002467 TIXMLASSERT( p <= q );
2468 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 Print( "%s", p );
2470 }
Lee Thomason857b8682012-01-25 17:50:25 -08002471}
2472
U-Stream\Leeae25a442012-02-17 17:48:16 -08002473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002474void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002477 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 -07002478 Print( "%s", bom );
2479 }
2480 if ( writeDec ) {
2481 PushDeclaration( "xml version=\"1.0\"" );
2482 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002483}
2484
2485
Uli Kusterer593a33d2014-02-01 12:48:51 +01002486void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002487{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002488 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002489 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002490
Uli Kusterer593a33d2014-02-01 12:48:51 +01002491 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002493 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002494 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002495 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002496 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002497
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002498 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002499 _elementJustOpened = true;
2500 _firstElement = false;
2501 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002502}
2503
2504
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002505void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002506{
Lee Thomason624d43f2012-10-12 10:58:48 -07002507 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 Print( " %s=\"", name );
2509 PrintString( value, false );
2510 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002511}
2512
2513
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002514void XMLPrinter::PushAttribute( const char* name, int v )
2515{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 char buf[BUF_SIZE];
2517 XMLUtil::ToStr( v, buf, BUF_SIZE );
2518 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002519}
2520
2521
2522void XMLPrinter::PushAttribute( const char* name, unsigned v )
2523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 char buf[BUF_SIZE];
2525 XMLUtil::ToStr( v, buf, BUF_SIZE );
2526 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002527}
2528
2529
Lee Thomason51c12712016-06-04 20:18:49 -07002530void XMLPrinter::PushAttribute(const char* name, int64_t v)
2531{
2532 char buf[BUF_SIZE];
2533 XMLUtil::ToStr(v, buf, BUF_SIZE);
2534 PushAttribute(name, buf);
2535}
2536
2537
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002538void XMLPrinter::PushAttribute( const char* name, bool v )
2539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002540 char buf[BUF_SIZE];
2541 XMLUtil::ToStr( v, buf, BUF_SIZE );
2542 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002543}
2544
2545
2546void XMLPrinter::PushAttribute( const char* name, double v )
2547{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 char buf[BUF_SIZE];
2549 XMLUtil::ToStr( v, buf, BUF_SIZE );
2550 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002551}
2552
2553
Uli Kustererca412e82014-02-01 13:35:05 +01002554void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002555{
Lee Thomason624d43f2012-10-12 10:58:48 -07002556 --_depth;
2557 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002558
Lee Thomason624d43f2012-10-12 10:58:48 -07002559 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 Print( "/>" );
2561 }
2562 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002563 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002564 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002565 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002566 }
2567 Print( "</%s>", name );
2568 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002569
Lee Thomason624d43f2012-10-12 10:58:48 -07002570 if ( _textDepth == _depth ) {
2571 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 }
Uli Kustererca412e82014-02-01 13:35:05 +01002573 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002574 Print( "\n" );
2575 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002576 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002577}
2578
2579
Dmitry-Mea092bc12014-12-23 17:57:05 +03002580void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002581{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002582 if ( !_elementJustOpened ) {
2583 return;
2584 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002585 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002586 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002587}
2588
2589
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002590void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002591{
Lee Thomason624d43f2012-10-12 10:58:48 -07002592 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002593
Dmitry-Mea092bc12014-12-23 17:57:05 +03002594 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002596 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002597 }
2598 else {
2599 PrintString( text, true );
2600 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002601}
2602
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002603void XMLPrinter::PushText( int64_t value )
2604{
2605 char buf[BUF_SIZE];
2606 XMLUtil::ToStr( value, buf, BUF_SIZE );
2607 PushText( buf, false );
2608}
2609
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002610void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002611{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 char buf[BUF_SIZE];
2613 XMLUtil::ToStr( value, buf, BUF_SIZE );
2614 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002615}
2616
2617
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002618void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002620 char buf[BUF_SIZE];
2621 XMLUtil::ToStr( value, buf, BUF_SIZE );
2622 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002623}
2624
2625
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002626void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002628 char buf[BUF_SIZE];
2629 XMLUtil::ToStr( value, buf, BUF_SIZE );
2630 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002631}
2632
2633
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002634void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002635{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002636 char buf[BUF_SIZE];
2637 XMLUtil::ToStr( value, buf, BUF_SIZE );
2638 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002639}
2640
2641
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002642void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002643{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 char buf[BUF_SIZE];
2645 XMLUtil::ToStr( value, buf, BUF_SIZE );
2646 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002647}
2648
Lee Thomason5cae8972012-01-24 18:03:07 -08002649
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002650void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002651{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002652 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002653 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002654 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002655 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002656 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002657 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002658 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002659}
Lee Thomason751da522012-02-10 08:50:51 -08002660
2661
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002662void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002663{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002664 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002665 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002667 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002668 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002669 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002670 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002671}
2672
2673
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002674void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002675{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002676 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002677 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002678 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002679 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002680 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002681 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002682 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002683}
2684
2685
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002686bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002687{
Lee Thomason624d43f2012-10-12 10:58:48 -07002688 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 if ( doc.HasBOM() ) {
2690 PushHeader( true, false );
2691 }
2692 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002693}
2694
2695
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002696bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002697{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002698 const XMLElement* parentElem = 0;
2699 if ( element.Parent() ) {
2700 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002701 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002702 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002703 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002704 while ( attribute ) {
2705 PushAttribute( attribute->Name(), attribute->Value() );
2706 attribute = attribute->Next();
2707 }
2708 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002709}
2710
2711
Uli Kustererca412e82014-02-01 13:35:05 +01002712bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002713{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002714 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002715 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002716}
2717
2718
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002719bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002721 PushText( text.Value(), text.CData() );
2722 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002723}
2724
2725
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002726bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002727{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002728 PushComment( comment.Value() );
2729 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002730}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002731
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002732bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002734 PushDeclaration( declaration.Value() );
2735 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002736}
2737
2738
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002739bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002740{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002741 PushUnknown( unknown.Value() );
2742 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002743}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002744
Lee Thomason685b8952012-11-12 13:00:06 -08002745} // namespace tinyxml2
2746