blob: 3ec4f6d46e60abdd7b3077a679a3d4308467f6db [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 Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 char endChar = *endTag;
201 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 // Inner loop of text parsing.
204 while ( *p ) {
205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
206 Set( start, p, strFlags );
207 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000208 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000209 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 }
211 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300212 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 }
214 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215}
216
217
218char* StrPair::ParseName( char* p )
219{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 return 0;
222 }
JayXonee525db2014-12-24 04:01:42 -0500223 if ( !XMLUtil::IsNameStartChar( *p ) ) {
224 return 0;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400227 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500228 ++p;
229 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 ++p;
231 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800232
JayXonee525db2014-12-24 04:01:42 -0500233 Set( start, p, 0 );
234 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235}
236
237
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238void StrPair::CollapseWhitespace()
239{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400240 // Adjusting _start would cause undefined behavior on delete[]
241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300245 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300246 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700248
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700249 while( *p ) {
250 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800251 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 if ( *p == 0 ) {
253 break; // don't write to q; this trims the trailing space.
254 }
255 *q = ' ';
256 ++q;
257 }
258 *q = *p;
259 ++q;
260 ++p;
261 }
262 *q = 0;
263 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700264}
265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267const char* StrPair::GetStr()
268{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300269 TIXMLASSERT( _start );
270 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags & NEEDS_FLUSH ) {
272 *_end = 0;
273 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300276 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700277 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800278
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 while( p < _end ) {
280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 // CR-LF pair becomes LF
282 // CR alone becomes LF
283 // LF-CR becomes LF
284 if ( *(p+1) == LF ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300290 *q = LF;
291 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 if ( *(p+1) == CR ) {
295 p += 2;
296 }
297 else {
298 ++p;
299 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300300 *q = LF;
301 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 // Entities handled by tinyXML2:
305 // - special entities in the entity table [in/out]
306 // - numeric character reference [in]
307 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400310 const int buflen = 10;
311 char buf[buflen] = { 0 };
312 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300313 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
448 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
Lee Thomason51c12712016-06-04 20:18:49 -0700585void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
591
Lee Thomason21be8822012-07-15 17:27:22 -0700592bool XMLUtil::ToInt( const char* str, int* value )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608bool XMLUtil::ToBool( const char* str, bool* value )
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 int ival = 0;
611 if ( ToInt( str, &ival )) {
612 *value = (ival==0) ? false : true;
613 return true;
614 }
615 if ( StringEqual( str, "true" ) ) {
616 *value = true;
617 return true;
618 }
619 else if ( StringEqual( str, "false" ) ) {
620 *value = false;
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
627bool XMLUtil::ToFloat( const char* str, float* value )
628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
630 return true;
631 }
632 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700633}
634
Lee Thomason51c12712016-06-04 20:18:49 -0700635
Lee Thomason21be8822012-07-15 17:27:22 -0700636bool XMLUtil::ToDouble( const char* str, double* value )
637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
639 return true;
640 }
641 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700642}
643
644
Lee Thomason51c12712016-06-04 20:18:49 -0700645bool XMLUtil::ToInt64(const char* str, int64_t* value)
646{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700647 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
648 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
649 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700650 return true;
651 }
652 return false;
653}
654
655
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700656char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657{
Dmitry-Me02384662015-03-03 16:02:13 +0300658 TIXMLASSERT( node );
659 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400660 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000661 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000662 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300663 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300664 *node = 0;
665 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 return p;
667 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Dmitry-Me962083b2015-05-26 11:38:30 +0300669 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 static const char* xmlHeader = { "<?" };
671 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300673 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 static const int xmlHeaderLen = 2;
677 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300679 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
683 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400684 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += xmlHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000692 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += commentHeaderLen;
694 }
695 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300696 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000698 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p += cdataHeaderLen;
700 text->SetCData( true );
701 }
702 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += dtdHeaderLen;
706 }
707 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += elementHeaderLen;
711 }
712 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000716 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718
Dmitry-Me02384662015-03-03 16:02:13 +0300719 TIXMLASSERT( returnNode );
720 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 *node = returnNode;
722 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723}
724
725
Lee Thomason751da522012-02-10 08:50:51 -0800726bool XMLDocument::Accept( XMLVisitor* visitor ) const
727{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300728 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 if ( visitor->VisitEnter( *this ) ) {
730 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
731 if ( !node->Accept( visitor ) ) {
732 break;
733 }
734 }
735 }
736 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800737}
Lee Thomason56bdd022012-02-09 18:16:58 -0800738
739
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740// --------- XMLNode ----------- //
741
742XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 _document( doc ),
744 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000745 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200747 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700748 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200749 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751}
752
753
754XMLNode::~XMLNode()
755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( _parent ) {
758 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760}
761
Michael Daumling21626882013-10-22 17:03:37 +0200762const char* XMLNode::Value() const
763{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300764 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530765 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530766 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200767 return _value.GetStr();
768}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800769
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800770void XMLNode::SetValue( const char* str, bool staticMem )
771{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 }
775 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800778}
779
Dmitry-Me3f63f212017-06-19 18:25:19 +0300780XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700781{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300782 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700783 if (!clone) return 0;
784
785 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300786 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700787 TIXMLASSERT(childClone);
788 clone->InsertEndChild(childClone);
789 }
790 return clone;
791}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800794{
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300796 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300797 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800800}
801
802
803void XMLNode::Unlink( XMLNode* child )
804{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300805 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300807 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700808 if ( child == _firstChild ) {
809 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 if ( child == _lastChild ) {
812 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomasond923c672012-01-23 08:44:25 -0800814
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 if ( child->_prev ) {
816 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 if ( child->_next ) {
819 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
Lee Thomason8a763612017-06-16 09:30:16 -0700821 child->_next = 0;
822 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700823 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824}
825
826
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827void XMLNode::DeleteChild( XMLNode* node )
828{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300829 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300830 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100832 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700833 TIXMLASSERT(node->_prev == 0);
834 TIXMLASSERT(node->_next == 0);
835 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400836 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800837}
838
839
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800840XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
841{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300842 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300843 if ( addThis->_document != _document ) {
844 TIXMLASSERT( false );
845 return 0;
846 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800847 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 if ( _lastChild ) {
850 TIXMLASSERT( _firstChild );
851 TIXMLASSERT( _lastChild->_next == 0 );
852 _lastChild->_next = addThis;
853 addThis->_prev = _lastChild;
854 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 TIXMLASSERT( _firstChild == 0 );
860 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800861
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 addThis->_prev = 0;
863 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800867}
868
869
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
871{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300872 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 if ( addThis->_document != _document ) {
874 TIXMLASSERT( false );
875 return 0;
876 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800877 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( _firstChild ) {
880 TIXMLASSERT( _lastChild );
881 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _firstChild->_prev = addThis;
884 addThis->_next = _firstChild;
885 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 TIXMLASSERT( _lastChild == 0 );
891 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 addThis->_prev = 0;
894 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700896 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400897 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898}
899
900
901XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
902{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300903 TIXMLASSERT( addThis );
904 if ( addThis->_document != _document ) {
905 TIXMLASSERT( false );
906 return 0;
907 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700908
Dmitry-Meabb2d042014-12-09 12:59:31 +0300909 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300912 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return 0;
914 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300915 if ( afterThis == addThis ) {
916 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
917 // Now AddThis must disappear from it's location and then
918 // reappear between BeforeThis and OneAfterAddThis.
919 // So just leave it where it is.
920 return addThis;
921 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800922
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 // The last node or the only node.
925 return InsertEndChild( addThis );
926 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800927 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 addThis->_prev = afterThis;
929 addThis->_next = afterThis->_next;
930 afterThis->_next->_prev = addThis;
931 afterThis->_next = addThis;
932 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800934}
935
936
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800960}
961
962
Dmitry-Me886ad972015-07-22 11:00:51 +0300963const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300965 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300966 const XMLElement* element = node->ToElementWithName( name );
967 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 }
971 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Dmitry-Me886ad972015-07-22 11:00:51 +0300975const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300977 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300978 const XMLElement* element = node->ToElementWithName( name );
979 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400980 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 }
983 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984}
985
986
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300987char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // This is a recursive method, but thinking about it "at the current level"
990 // it is a pretty simple flat list:
991 // <foo/>
992 // <!-- comment -->
993 //
994 // With a special case:
995 // <foo>
996 // </foo>
997 // <!-- comment -->
998 //
999 // Where the closing element (/foo) *must* be the next thing after the opening
1000 // element, and the names must match. BUT the tricky bit is that the closing
1001 // element will be read by the child.
1002 //
1003 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1004 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 while( p && *p ) {
1007 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001008
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001010 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001011 if ( node == 0 ) {
1012 break;
1013 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014
kezenatore3531812016-11-29 19:49:07 +10001015 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001016
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001018 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001020 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001022 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 break;
1025 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301027 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301028 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001029 // Declarations are only allowed at document level
1030 bool wellLocated = ( ToDocument() != 0 );
1031 if ( wellLocated ) {
1032 // Multiple declarations are allowed but all declarations
1033 // must occur before anything else
1034 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1035 if ( !existingNode->ToDeclaration() ) {
1036 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301037 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001038 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301039 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001040 }
1041 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001042 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001043 DeleteNode( node );
1044 break;
1045 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301046 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301047
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001048 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001050 // We read the end tag. Return it to the parent.
1051 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001052 if ( parentEndTag ) {
1053 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001054 }
1055 node->_memPool->SetTracked(); // created and then immediately deleted.
1056 DeleteNode( node );
1057 return p;
1058 }
1059
1060 // Handle an end tag returned to this level.
1061 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001062 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001063 if ( endTag.Empty() ) {
1064 if ( ele->ClosingType() == XMLElement::OPEN ) {
1065 mismatch = true;
1066 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001068 else {
1069 if ( ele->ClosingType() != XMLElement::OPEN ) {
1070 mismatch = true;
1071 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001072 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001073 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
1075 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001076 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001077 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001078 DeleteNode( node );
1079 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001080 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 }
JayXondbfdd8f2014-12-12 20:07:14 -05001082 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 }
1084 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001085}
1086
Lee Thomason816d3fa2017-06-05 14:35:55 -07001087/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001088{
1089 if ( node == 0 ) {
1090 return;
1091 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001092 TIXMLASSERT(node->_document);
1093 if (!node->ToDocument()) {
1094 node->_document->MarkInUse(node);
1095 }
1096
Dmitry-Mee3225b12014-09-03 11:03:11 +04001097 MemPool* pool = node->_memPool;
1098 node->~XMLNode();
1099 pool->Free( node );
1100}
1101
Lee Thomason3cebdc42015-01-05 17:16:28 -08001102void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001103{
1104 TIXMLASSERT( insertThis );
1105 TIXMLASSERT( insertThis->_document == _document );
1106
Lee Thomason816d3fa2017-06-05 14:35:55 -07001107 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001108 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001109 }
1110 else {
1111 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001112 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001113 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001114}
1115
Dmitry-Meecb9b072016-10-12 16:44:59 +03001116const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1117{
1118 const XMLElement* element = this->ToElement();
1119 if ( element == 0 ) {
1120 return 0;
1121 }
1122 if ( name == 0 ) {
1123 return element;
1124 }
1125 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1126 return element;
1127 }
1128 return 0;
1129}
1130
Lee Thomason5492a1c2012-01-23 15:32:10 -08001131// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001132char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 const char* start = p;
1135 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001138 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 return p;
1141 }
1142 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001143 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1144 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001145 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001147
kezenator4f756162016-11-29 19:46:27 +10001148 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( p && *p ) {
1150 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001151 }
1152 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001153 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 }
1155 }
1156 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001157}
1158
1159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 }
1165 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1166 text->SetCData( this->CData() );
1167 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
1171bool XMLText::ShallowEqual( const XMLNode* compare ) const
1172{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001173 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001174 const XMLText* text = compare->ToText();
1175 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001176}
1177
1178
Lee Thomason56bdd022012-02-09 18:16:58 -08001179bool XMLText::Accept( XMLVisitor* visitor ) const
1180{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001181 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001183}
1184
1185
Lee Thomason3f57d272012-01-11 15:30:03 -08001186// --------- XMLComment ---------- //
1187
Lee Thomasone4422302012-01-20 17:59:50 -08001188XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001189{
1190}
1191
1192
Lee Thomasonce0763e2012-01-11 15:43:54 -08001193XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001194{
Lee Thomason3f57d272012-01-11 15:30:03 -08001195}
1196
1197
kezenator4f756162016-11-29 19:46:27 +10001198char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 // Comment parses as text.
1201 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001202 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001204 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 }
1206 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001207}
1208
1209
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
1215 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1216 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217}
1218
1219
1220bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1221{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001222 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001223 const XMLComment* comment = compare->ToComment();
1224 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001225}
1226
1227
Lee Thomason751da522012-02-10 08:50:51 -08001228bool XMLComment::Accept( XMLVisitor* visitor ) const
1229{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001230 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001232}
Lee Thomason56bdd022012-02-09 18:16:58 -08001233
1234
Lee Thomason50f97b22012-02-11 16:33:40 -08001235// --------- XMLDeclaration ---------- //
1236
1237XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1238{
1239}
1240
1241
1242XMLDeclaration::~XMLDeclaration()
1243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247
kezenator4f756162016-11-29 19:46:27 +10001248char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 // Declaration parses as text.
1251 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001252 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001254 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 }
1256 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
1259
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 }
1265 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1266 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001267}
1268
1269
1270bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1271{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001272 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001273 const XMLDeclaration* declaration = compare->ToDeclaration();
1274 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001275}
1276
1277
1278
Lee Thomason50f97b22012-02-11 16:33:40 -08001279bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1280{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001281 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001283}
1284
1285// --------- XMLUnknown ---------- //
1286
1287XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1288{
1289}
1290
1291
1292XMLUnknown::~XMLUnknown()
1293{
1294}
1295
1296
kezenator4f756162016-11-29 19:46:27 +10001297char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 // Unknown parses as text.
1300 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301
kezenator4f756162016-11-29 19:46:27 +10001302 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001304 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 }
1306 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001307}
1308
1309
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001310XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1316 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001317}
1318
1319
1320bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1321{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001322 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001323 const XMLUnknown* unknown = compare->ToUnknown();
1324 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001325}
1326
1327
Lee Thomason50f97b22012-02-11 16:33:40 -08001328bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1329{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001330 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001332}
1333
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001335
1336const char* XMLAttribute::Name() const
1337{
1338 return _name.GetStr();
1339}
1340
1341const char* XMLAttribute::Value() const
1342{
1343 return _value.GetStr();
1344}
1345
kezenator4f756162016-11-29 19:46:27 +10001346char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( !p || !*p ) {
1351 return 0;
1352 }
Lee Thomason22aead12012-01-23 13:29:35 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001355 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001356 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return 0;
1358 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001359
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001361 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( *p != '\"' && *p != '\'' ) {
1363 return 0;
1364 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001365
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 char endTag[2] = { *p, 0 };
1367 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001368
kezenator4f756162016-11-29 19:46:27 +10001369 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371}
1372
1373
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001374void XMLAttribute::SetName( const char* n )
1375{
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001377}
1378
1379
Lee Thomason2fa81722012-11-09 12:37:46 -08001380XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001383 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
1385 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason2fa81722012-11-09 12:37:46 -08001389XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001392 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001395}
1396
1397
Lee Thomason51c12712016-06-04 20:18:49 -07001398XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1399{
1400 if (XMLUtil::ToInt64(Value(), value)) {
1401 return XML_SUCCESS;
1402 }
1403 return XML_WRONG_ATTRIBUTE_TYPE;
1404}
1405
1406
Lee Thomason2fa81722012-11-09 12:37:46 -08001407XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001410 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 }
1412 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413}
1414
1415
Lee Thomason2fa81722012-11-09 12:37:46 -08001416XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001419 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
Lee Thomason2fa81722012-11-09 12:37:46 -08001425XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001428 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 }
1430 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001431}
1432
1433
1434void XMLAttribute::SetAttribute( const char* v )
1435{
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437}
1438
1439
Lee Thomason1ff38e02012-02-14 18:18:16 -08001440void XMLAttribute::SetAttribute( int 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 Thomason1ff38e02012-02-14 18:18:16 -08001445}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446
1447
1448void XMLAttribute::SetAttribute( unsigned v )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453}
1454
1455
Lee Thomason51c12712016-06-04 20:18:49 -07001456void XMLAttribute::SetAttribute(int64_t v)
1457{
1458 char buf[BUF_SIZE];
1459 XMLUtil::ToStr(v, buf, BUF_SIZE);
1460 _value.SetStr(buf);
1461}
1462
1463
1464
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465void XMLAttribute::SetAttribute( bool v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472void XMLAttribute::SetAttribute( double v )
1473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
1479void XMLAttribute::SetAttribute( float v )
1480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 char buf[BUF_SIZE];
1482 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001484}
1485
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001486
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001487// --------- XMLElement ---------- //
1488XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001489 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491{
1492}
1493
1494
1495XMLElement::~XMLElement()
1496{
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 while( _rootAttribute ) {
1498 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001499 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001502}
1503
1504
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1506{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001507 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1509 return a;
1510 }
1511 }
1512 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001513}
1514
1515
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001516const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 const XMLAttribute* a = FindAttribute( name );
1519 if ( !a ) {
1520 return 0;
1521 }
1522 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1523 return a->Value();
1524 }
1525 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001526}
1527
Josh Wittnercf3dd092016-10-11 18:57:17 -07001528int XMLElement::IntAttribute(const char* name, int defaultValue) const
1529{
1530 int i = defaultValue;
1531 QueryIntAttribute(name, &i);
1532 return i;
1533}
1534
1535unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1536{
1537 unsigned i = defaultValue;
1538 QueryUnsignedAttribute(name, &i);
1539 return i;
1540}
1541
1542int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1543{
1544 int64_t i = defaultValue;
1545 QueryInt64Attribute(name, &i);
1546 return i;
1547}
1548
1549bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1550{
1551 bool b = defaultValue;
1552 QueryBoolAttribute(name, &b);
1553 return b;
1554}
1555
1556double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1557{
1558 double d = defaultValue;
1559 QueryDoubleAttribute(name, &d);
1560 return d;
1561}
1562
1563float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1564{
1565 float f = defaultValue;
1566 QueryFloatAttribute(name, &f);
1567 return f;
1568}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001569
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001570const char* XMLElement::GetText() const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001573 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576}
1577
1578
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001579void XMLElement::SetText( const char* inText )
1580{
Uli Kusterer869bb592014-01-21 01:36:16 +01001581 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001582 FirstChild()->SetValue( inText );
1583 else {
1584 XMLText* theText = GetDocument()->NewText( inText );
1585 InsertFirstChild( theText );
1586 }
1587}
1588
Lee Thomason5bb2d802014-01-24 10:42:57 -08001589
1590void XMLElement::SetText( int v )
1591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
1598void XMLElement::SetText( unsigned v )
1599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr( v, buf, BUF_SIZE );
1602 SetText( buf );
1603}
1604
1605
Lee Thomason51c12712016-06-04 20:18:49 -07001606void XMLElement::SetText(int64_t v)
1607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr(v, buf, BUF_SIZE);
1610 SetText(buf);
1611}
1612
1613
1614void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001615{
1616 char buf[BUF_SIZE];
1617 XMLUtil::ToStr( v, buf, BUF_SIZE );
1618 SetText( buf );
1619}
1620
1621
1622void XMLElement::SetText( float v )
1623{
1624 char buf[BUF_SIZE];
1625 XMLUtil::ToStr( v, buf, BUF_SIZE );
1626 SetText( buf );
1627}
1628
1629
1630void XMLElement::SetText( double v )
1631{
1632 char buf[BUF_SIZE];
1633 XMLUtil::ToStr( v, buf, BUF_SIZE );
1634 SetText( buf );
1635}
1636
1637
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001641 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001642 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
Lee Thomason51c12712016-06-04 20:18:49 -07001664XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1665{
1666 if (FirstChild() && FirstChild()->ToText()) {
1667 const char* t = FirstChild()->Value();
1668 if (XMLUtil::ToInt64(t, ival)) {
1669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
1674}
1675
1676
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001680 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001681 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 return XML_SUCCESS;
1683 }
1684 return XML_CAN_NOT_CONVERT_TEXT;
1685 }
1686 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001687}
1688
1689
MortenMacFly4ee49f12013-01-14 20:03:14 +01001690XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001693 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001694 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 return XML_SUCCESS;
1696 }
1697 return XML_CAN_NOT_CONVERT_TEXT;
1698 }
1699 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001700}
1701
1702
MortenMacFly4ee49f12013-01-14 20:03:14 +01001703XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001706 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001707 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 return XML_SUCCESS;
1709 }
1710 return XML_CAN_NOT_CONVERT_TEXT;
1711 }
1712 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001713}
1714
Josh Wittnercf3dd092016-10-11 18:57:17 -07001715int XMLElement::IntText(int defaultValue) const
1716{
1717 int i = defaultValue;
1718 QueryIntText(&i);
1719 return i;
1720}
1721
1722unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1723{
1724 unsigned i = defaultValue;
1725 QueryUnsignedText(&i);
1726 return i;
1727}
1728
1729int64_t XMLElement::Int64Text(int64_t defaultValue) const
1730{
1731 int64_t i = defaultValue;
1732 QueryInt64Text(&i);
1733 return i;
1734}
1735
1736bool XMLElement::BoolText(bool defaultValue) const
1737{
1738 bool b = defaultValue;
1739 QueryBoolText(&b);
1740 return b;
1741}
1742
1743double XMLElement::DoubleText(double defaultValue) const
1744{
1745 double d = defaultValue;
1746 QueryDoubleText(&d);
1747 return d;
1748}
1749
1750float XMLElement::FloatText(float defaultValue) const
1751{
1752 float f = defaultValue;
1753 QueryFloatText(&f);
1754 return f;
1755}
Lee Thomason21be8822012-07-15 17:27:22 -07001756
1757
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001758XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1759{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 XMLAttribute* last = 0;
1761 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1766 break;
1767 }
1768 }
1769 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001770 attrib = CreateAttribute();
1771 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001773 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001777 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 attrib->SetName( name );
1781 }
1782 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001783}
1784
1785
U-Stream\Leeae25a442012-02-17 17:48:16 -08001786void XMLElement::DeleteAttribute( const char* name )
1787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1791 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001797 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 break;
1799 }
1800 prev = a;
1801 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001802}
1803
1804
kezenator4f756162016-11-29 19:46:27 +10001805char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 const char* start = p;
1808 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001809
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 // Read the attributes.
1811 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001812 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001813 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001814 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 return 0;
1816 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001817
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001819 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001820 XMLAttribute* attrib = CreateAttribute();
1821 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001822 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001823
kezenatorec694152016-11-26 17:21:43 +10001824 int attrLineNum = attrib->_parseLineNum;
1825
kezenator4f756162016-11-29 19:46:27 +10001826 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001828 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001829 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 return 0;
1831 }
1832 // There is a minor bug here: if the attribute in the source xml
1833 // document is duplicated, it will not be detected and the
1834 // attribute will be doubly added. However, tracking the 'prevAttribute'
1835 // avoids re-scanning the attribute list. Preferring performance for
1836 // now, may reconsider in the future.
1837 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001838 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 }
1841 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001842 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 }
1845 prevAttribute = attrib;
1846 }
1847 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 else if ( *p == '>' ) {
1849 ++p;
1850 break;
1851 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001852 // end of the tag
1853 else if ( *p == '/' && *(p+1) == '>' ) {
1854 _closingType = CLOSED;
1855 return p+2; // done; sealed element.
1856 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001858 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 return 0;
1860 }
1861 }
1862 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001863}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001864
Dmitry-Mee3225b12014-09-03 11:03:11 +04001865void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1866{
1867 if ( attribute == 0 ) {
1868 return;
1869 }
1870 MemPool* pool = attribute->_memPool;
1871 attribute->~XMLAttribute();
1872 pool->Free( attribute );
1873}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001874
Dmitry-Mea60caa22016-11-22 18:28:08 +03001875XMLAttribute* XMLElement::CreateAttribute()
1876{
1877 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1878 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001879 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001880 attrib->_memPool = &_document->_attributePool;
1881 attrib->_memPool->SetTracked();
1882 return attrib;
1883}
1884
Lee Thomason67d61312012-01-24 16:01:51 -08001885//
1886// <ele></ele>
1887// <ele>foo<b>bar</b></ele>
1888//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001889char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001890{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001892 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001893
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 // The closing element is the </element> form. It is
1895 // parsed just like a regular element then deleted from
1896 // the DOM.
1897 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 ++p;
1900 }
Lee Thomason67d61312012-01-24 16:01:51 -08001901
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 p = _value.ParseName( p );
1903 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 return 0;
1905 }
Lee Thomason67d61312012-01-24 16:01:51 -08001906
kezenator4f756162016-11-29 19:46:27 +10001907 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001908 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return p;
1910 }
Lee Thomason67d61312012-01-24 16:01:51 -08001911
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001912 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001914}
1915
1916
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001917
1918XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
1923 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1924 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1925 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1926 }
1927 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
1930
1931bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1932{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001933 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001935 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001936
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 const XMLAttribute* a=FirstAttribute();
1938 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001939
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 while ( a && b ) {
1941 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1942 return false;
1943 }
1944 a = a->Next();
1945 b = b->Next();
1946 }
1947 if ( a || b ) {
1948 // different count
1949 return false;
1950 }
1951 return true;
1952 }
1953 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001954}
1955
1956
Lee Thomason751da522012-02-10 08:50:51 -08001957bool XMLElement::Accept( XMLVisitor* visitor ) const
1958{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001959 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1962 if ( !node->Accept( visitor ) ) {
1963 break;
1964 }
1965 }
1966 }
1967 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001968}
Lee Thomason56bdd022012-02-09 18:16:58 -08001969
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001970
Lee Thomason3f57d272012-01-11 15:30:03 -08001971// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001972
1973// Warning: List must match 'enum XMLError'
1974const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1975 "XML_SUCCESS",
1976 "XML_NO_ATTRIBUTE",
1977 "XML_WRONG_ATTRIBUTE_TYPE",
1978 "XML_ERROR_FILE_NOT_FOUND",
1979 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1980 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001981 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001982 "XML_ERROR_PARSING_ELEMENT",
1983 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001984 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001985 "XML_ERROR_PARSING_TEXT",
1986 "XML_ERROR_PARSING_CDATA",
1987 "XML_ERROR_PARSING_COMMENT",
1988 "XML_ERROR_PARSING_DECLARATION",
1989 "XML_ERROR_PARSING_UNKNOWN",
1990 "XML_ERROR_EMPTY_DOCUMENT",
1991 "XML_ERROR_MISMATCHED_ELEMENT",
1992 "XML_ERROR_PARSING",
1993 "XML_CAN_NOT_CONVERT_TEXT",
1994 "XML_NO_TEXT_NODE"
1995};
1996
1997
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001998XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _writeBOM( false ),
2001 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002002 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002003 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002004 _errorLineNum( 0 ),
2005 _charBuffer( 0 ),
2006 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08002007{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002008 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2009 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002010}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002011
2012
Lee Thomason3f57d272012-01-11 15:30:03 -08002013XMLDocument::~XMLDocument()
2014{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002015 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002016}
2017
2018
Lee Thomason816d3fa2017-06-05 14:35:55 -07002019void XMLDocument::MarkInUse(XMLNode* node)
2020{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002021 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002022 TIXMLASSERT(node->_parent == 0);
2023
2024 for (int i = 0; i < _unlinked.Size(); ++i) {
2025 if (node == _unlinked[i]) {
2026 _unlinked.SwapRemove(i);
2027 break;
2028 }
2029 }
2030}
2031
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002032void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002033{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002034 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002035 while( _unlinked.Size()) {
2036 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2037 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002038
Dmitry-Meab37df82014-11-28 12:08:36 +03002039#ifdef DEBUG
2040 const bool hadError = Error();
2041#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002042 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 delete [] _charBuffer;
2045 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002046
2047#if 0
2048 _textPool.Trace( "text" );
2049 _elementPool.Trace( "element" );
2050 _commentPool.Trace( "comment" );
2051 _attributePool.Trace( "attribute" );
2052#endif
2053
2054#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002055 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002056 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2057 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2058 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2059 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2060 }
2061#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002062}
2063
Lee Thomason3f57d272012-01-11 15:30:03 -08002064
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002065void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002066{
2067 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002068 if (target == this) {
2069 return; // technically success - a no-op.
2070 }
Lee Thomason7085f002017-06-01 18:09:43 -07002071
2072 target->Clear();
2073 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2074 target->InsertEndChild(node->DeepClone(target));
2075 }
2076}
2077
Lee Thomason2c85a712012-01-31 08:24:24 -08002078XMLElement* XMLDocument::NewElement( const char* name )
2079{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002080 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 ele->SetName( name );
2082 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002083}
2084
2085
Lee Thomason1ff38e02012-02-14 18:18:16 -08002086XMLComment* XMLDocument::NewComment( const char* str )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 comment->SetValue( str );
2090 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002091}
2092
2093
2094XMLText* XMLDocument::NewText( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 text->SetValue( str );
2098 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002099}
2100
2101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2106 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
2109
2110XMLUnknown* XMLDocument::NewUnknown( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 unk->SetValue( str );
2114 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
Dmitry-Me01578db2014-08-19 10:18:48 +04002117static FILE* callfopen( const char* filepath, const char* mode )
2118{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002119 TIXMLASSERT( filepath );
2120 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002121#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2122 FILE* fp = 0;
2123 errno_t err = fopen_s( &fp, filepath, mode );
2124 if ( err ) {
2125 return 0;
2126 }
2127#else
2128 FILE* fp = fopen( filepath, mode );
2129#endif
2130 return fp;
2131}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002132
2133void XMLDocument::DeleteNode( XMLNode* node ) {
2134 TIXMLASSERT( node );
2135 TIXMLASSERT(node->_document == this );
2136 if (node->_parent) {
2137 node->_parent->DeleteChild( node );
2138 }
2139 else {
2140 // Isn't in the tree.
2141 // Use the parent delete.
2142 // Also, we need to mark it tracked: we 'know'
2143 // it was never used.
2144 node->_memPool->SetTracked();
2145 // Call the static XMLNode version:
2146 XMLNode::DeleteNode(node);
2147 }
2148}
2149
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002150
Lee Thomason2fa81722012-11-09 12:37:46 -08002151XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002153 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002154 FILE* fp = callfopen( filename, "rb" );
2155 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002156 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
2159 LoadFile( fp );
2160 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162}
2163
Dmitry-Me901fed52015-09-25 10:29:51 +03002164// This is likely overengineered template art to have a check that unsigned long value incremented
2165// by one still fits into size_t. If size_t type is larger than unsigned long type
2166// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2167// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2168// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2169// types sizes relate to each other.
2170template
2171<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2172struct LongFitsIntoSizeTMinusOne {
2173 static bool Fits( unsigned long value )
2174 {
2175 return value < (size_t)-1;
2176 }
2177};
2178
2179template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002180struct LongFitsIntoSizeTMinusOne<false> {
2181 static bool Fits( unsigned long )
2182 {
2183 return true;
2184 }
2185};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186
Lee Thomason2fa81722012-11-09 12:37:46 -08002187XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002189 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002190
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002191 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002192 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002193 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002194 return _errorID;
2195 }
2196
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002198 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002200 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002201 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002202 return _errorID;
2203 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002204 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002205
Dmitry-Me901fed52015-09-25 10:29:51 +03002206 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002207 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002208 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002209 return _errorID;
2210 }
2211
Dmitry-Me72801b82015-05-07 09:41:39 +03002212 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002213 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002216
Dmitry-Me72801b82015-05-07 09:41:39 +03002217 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002218 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 _charBuffer = new char[size+1];
2220 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002222 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002225
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227
Dmitry-Me97476b72015-01-01 16:15:57 +03002228 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230}
2231
2232
Lee Thomason2fa81722012-11-09 12:37:46 -08002233XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Dmitry-Me01578db2014-08-19 10:18:48 +04002235 FILE* fp = callfopen( filename, "w" );
2236 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002237 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
2240 SaveFile(fp, compact);
2241 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002243}
2244
2245
Lee Thomason2fa81722012-11-09 12:37:46 -08002246XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002247{
Ant Mitchell189198f2015-03-24 16:20:36 +00002248 // Clear any error from the last save, otherwise it will get reported
2249 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002250 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 XMLPrinter stream( fp, compact );
2252 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
Lee Thomason1ff38e02012-02-14 18:18:16 -08002256
Lee Thomason2fa81722012-11-09 12:37:46 -08002257XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002258{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002259 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002260
Lee Thomason82d32002014-02-21 22:47:18 -08002261 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002262 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
2265 if ( len == (size_t)(-1) ) {
2266 len = strlen( p );
2267 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002268 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 _charBuffer = new char[ len+1 ];
2270 memcpy( _charBuffer, p, len );
2271 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002272
Dmitry-Me97476b72015-01-01 16:15:57 +03002273 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002274 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002275 // clean up now essentially dangling memory.
2276 // and the parse fail can put objects in the
2277 // pools that are dead and inaccessible.
2278 DeleteChildren();
2279 _elementPool.Clear();
2280 _attributePool.Clear();
2281 _textPool.Clear();
2282 _commentPool.Clear();
2283 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002285}
2286
2287
PKEuS1c5f99e2013-07-06 11:28:39 +02002288void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002289{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002290 if ( streamer ) {
2291 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002293 else {
2294 XMLPrinter stdoutStreamer( stdout );
2295 Accept( &stdoutStreamer );
2296 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002297}
2298
2299
Lee Thomasonaa188392017-09-19 17:54:31 -07002300void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002301{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002302 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002304 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002305 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002306
Lee Thomasonaa188392017-09-19 17:54:31 -07002307 if (format) {
2308 size_t BUFFER_SIZE = 1000;
2309 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonf49b9652017-10-11 10:57:49 -07002310 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum);
Lee Thomasonaa188392017-09-19 17:54:31 -07002311 size_t len = strlen(buffer);
2312
2313 va_list va;
2314 va_start( va, format );
2315 int result = TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );
2316 va_end( va );
2317
2318 _errorStr.SetStr(buffer);
2319 delete [] buffer;
2320 }
Lee Thomason67d61312012-01-24 16:01:51 -08002321}
2322
Lee Thomasonaa188392017-09-19 17:54:31 -07002323
Lee Thomasone90e9012016-12-24 07:34:39 -08002324/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002325{
kezenator5a700712016-11-26 13:54:42 +10002326 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2327 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002328 TIXMLASSERT( errorName && errorName[0] );
2329 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002330}
Lee Thomason5cae8972012-01-24 18:03:07 -08002331
Lee Thomasonf49b9652017-10-11 10:57:49 -07002332const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002333{
Lee Thomasonaa188392017-09-19 17:54:31 -07002334 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002335}
2336
Lee Thomasonf49b9652017-10-11 10:57:49 -07002337
2338void XMLDocument::PrintError() const
2339{
2340 printf("%s\n", ErrorStr());
2341}
2342
kezenator5a700712016-11-26 13:54:42 +10002343const char* XMLDocument::ErrorName() const
2344{
Lee Thomasone90e9012016-12-24 07:34:39 -08002345 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002346}
2347
Dmitry-Me97476b72015-01-01 16:15:57 +03002348void XMLDocument::Parse()
2349{
2350 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2351 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002352 _parseCurLineNum = 1;
2353 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002354 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002355 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002356 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002357 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002358 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002359 return;
2360 }
kezenator4f756162016-11-29 19:46:27 +10002361 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002362}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002363
PKEuS1bfb9542013-08-04 13:51:17 +02002364XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002365 _elementJustOpened( false ),
2366 _firstElement( true ),
2367 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002368 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 _textDepth( -1 ),
2370 _processEntities( true ),
2371 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 _entityFlag[i] = false;
2375 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 }
2377 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002378 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002379 const unsigned char flagIndex = (unsigned char)entityValue;
2380 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2381 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002383 _restrictedEntityFlag[(unsigned char)'&'] = true;
2384 _restrictedEntityFlag[(unsigned char)'<'] = true;
2385 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002387}
2388
2389
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002390void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002391{
2392 va_list va;
2393 va_start( va, format );
2394
Lee Thomason624d43f2012-10-12 10:58:48 -07002395 if ( _fp ) {
2396 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 }
2398 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002399 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 // Close out and re-start the va-args
2401 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002402 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002404 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002405 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002406 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002408 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002409}
2410
2411
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002412void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 for( int i=0; i<depth; ++i ) {
2415 Print( " " );
2416 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002417}
2418
2419
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002420void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 // Look for runs of bytes between entities to print.
2423 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002424
Lee Thomason624d43f2012-10-12 10:58:48 -07002425 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002426 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002428 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002429 // Remember, char is sometimes signed. (How many times has that bitten me?)
2430 if ( *q > 0 && *q < ENTITY_RANGE ) {
2431 // Check for entities. If one is found, flush
2432 // the stream up until the entity, write the
2433 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002434 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002435 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002436 const size_t delta = q - p;
2437 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002438 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002439 Print( "%.*s", toPrint, p );
2440 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002442 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002443 for( int i=0; i<NUM_ENTITIES; ++i ) {
2444 if ( entities[i].value == *q ) {
2445 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002446 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 break;
2448 }
2449 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002450 if ( !entityPatternPrinted ) {
2451 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2452 TIXMLASSERT( false );
2453 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 ++p;
2455 }
2456 }
2457 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002458 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002459 }
2460 }
2461 // Flush the remaining string. This will be the entire
2462 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002463 TIXMLASSERT( p <= q );
2464 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 Print( "%s", p );
2466 }
Lee Thomason857b8682012-01-25 17:50:25 -08002467}
2468
U-Stream\Leeae25a442012-02-17 17:48:16 -08002469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002470void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002471{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002472 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002473 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 -07002474 Print( "%s", bom );
2475 }
2476 if ( writeDec ) {
2477 PushDeclaration( "xml version=\"1.0\"" );
2478 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002479}
2480
2481
Uli Kusterer593a33d2014-02-01 12:48:51 +01002482void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002483{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002484 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002485 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002486
Uli Kusterer593a33d2014-02-01 12:48:51 +01002487 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002488 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002489 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002490 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002491 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002493
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002494 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002495 _elementJustOpened = true;
2496 _firstElement = false;
2497 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002498}
2499
2500
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002501void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002502{
Lee Thomason624d43f2012-10-12 10:58:48 -07002503 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 Print( " %s=\"", name );
2505 PrintString( value, false );
2506 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002507}
2508
2509
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002510void XMLPrinter::PushAttribute( const char* name, int v )
2511{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002512 char buf[BUF_SIZE];
2513 XMLUtil::ToStr( v, buf, BUF_SIZE );
2514 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002515}
2516
2517
2518void XMLPrinter::PushAttribute( const char* name, unsigned v )
2519{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002520 char buf[BUF_SIZE];
2521 XMLUtil::ToStr( v, buf, BUF_SIZE );
2522 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002523}
2524
2525
Lee Thomason51c12712016-06-04 20:18:49 -07002526void XMLPrinter::PushAttribute(const char* name, int64_t v)
2527{
2528 char buf[BUF_SIZE];
2529 XMLUtil::ToStr(v, buf, BUF_SIZE);
2530 PushAttribute(name, buf);
2531}
2532
2533
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002534void XMLPrinter::PushAttribute( const char* name, bool v )
2535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002536 char buf[BUF_SIZE];
2537 XMLUtil::ToStr( v, buf, BUF_SIZE );
2538 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002539}
2540
2541
2542void XMLPrinter::PushAttribute( const char* name, double v )
2543{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 char buf[BUF_SIZE];
2545 XMLUtil::ToStr( v, buf, BUF_SIZE );
2546 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002547}
2548
2549
Uli Kustererca412e82014-02-01 13:35:05 +01002550void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002551{
Lee Thomason624d43f2012-10-12 10:58:48 -07002552 --_depth;
2553 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002554
Lee Thomason624d43f2012-10-12 10:58:48 -07002555 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 Print( "/>" );
2557 }
2558 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002559 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002561 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002562 }
2563 Print( "</%s>", name );
2564 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002565
Lee Thomason624d43f2012-10-12 10:58:48 -07002566 if ( _textDepth == _depth ) {
2567 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002568 }
Uli Kustererca412e82014-02-01 13:35:05 +01002569 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 Print( "\n" );
2571 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002572 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002573}
2574
2575
Dmitry-Mea092bc12014-12-23 17:57:05 +03002576void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002577{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002578 if ( !_elementJustOpened ) {
2579 return;
2580 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002581 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002583}
2584
2585
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002586void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002587{
Lee Thomason624d43f2012-10-12 10:58:48 -07002588 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002589
Dmitry-Mea092bc12014-12-23 17:57:05 +03002590 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002591 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002592 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 }
2594 else {
2595 PrintString( text, true );
2596 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002597}
2598
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002599void XMLPrinter::PushText( int64_t value )
2600{
2601 char buf[BUF_SIZE];
2602 XMLUtil::ToStr( value, buf, BUF_SIZE );
2603 PushText( buf, false );
2604}
2605
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002606void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002608 char buf[BUF_SIZE];
2609 XMLUtil::ToStr( value, buf, BUF_SIZE );
2610 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002611}
2612
2613
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002614void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002616 char buf[BUF_SIZE];
2617 XMLUtil::ToStr( value, buf, BUF_SIZE );
2618 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002619}
2620
2621
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002622void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002624 char buf[BUF_SIZE];
2625 XMLUtil::ToStr( value, buf, BUF_SIZE );
2626 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002627}
2628
2629
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002630void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002631{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 char buf[BUF_SIZE];
2633 XMLUtil::ToStr( value, buf, BUF_SIZE );
2634 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002635}
2636
2637
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002638void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002640 char buf[BUF_SIZE];
2641 XMLUtil::ToStr( value, buf, BUF_SIZE );
2642 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002643}
2644
Lee Thomason5cae8972012-01-24 18:03:07 -08002645
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002646void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002647{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002648 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002649 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002651 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002653 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002654 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002655}
Lee Thomason751da522012-02-10 08:50:51 -08002656
2657
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002658void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002659{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002660 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002661 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002662 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002665 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002667}
2668
2669
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002670void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002671{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002672 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002673 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002674 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002675 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002677 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002678 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002679}
2680
2681
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002682bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002683{
Lee Thomason624d43f2012-10-12 10:58:48 -07002684 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002685 if ( doc.HasBOM() ) {
2686 PushHeader( true, false );
2687 }
2688 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002689}
2690
2691
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002692bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002693{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002694 const XMLElement* parentElem = 0;
2695 if ( element.Parent() ) {
2696 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002697 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002698 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002699 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002700 while ( attribute ) {
2701 PushAttribute( attribute->Name(), attribute->Value() );
2702 attribute = attribute->Next();
2703 }
2704 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002705}
2706
2707
Uli Kustererca412e82014-02-01 13:35:05 +01002708bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002709{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002710 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002712}
2713
2714
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002715bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002716{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002717 PushText( text.Value(), text.CData() );
2718 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002719}
2720
2721
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002722bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002723{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002724 PushComment( comment.Value() );
2725 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002726}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002727
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002728bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002729{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002730 PushDeclaration( declaration.Value() );
2731 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002732}
2733
2734
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002735bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002736{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002737 PushUnknown( unknown.Value() );
2738 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002739}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002740
Lee Thomason685b8952012-11-12 13:00:06 -08002741} // namespace tinyxml2
2742