blob: c74950f944be4ba8d4beaf8df0510b96e791475b [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
Lee Thomason29658802014-11-27 22:31:11 -0800152 TIXMLASSERT( other->_flags == 0 );
153 TIXMLASSERT( other->_start == 0 );
154 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300155
Lee Thomason29658802014-11-27 22:31:11 -0800156 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300157
Lee Thomason29658802014-11-27 22:31:11 -0800158 other->_flags = _flags;
159 other->_start = _start;
160 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300161
162 _flags = 0;
163 _start = 0;
164 _end = 0;
165}
166
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800167void StrPair::Reset()
168{
Lee Thomason120b3a62012-10-12 10:06:59 -0700169 if ( _flags & NEEDS_DELETE ) {
170 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700171 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700172 _flags = 0;
173 _start = 0;
174 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800175}
176
177
178void StrPair::SetStr( const char* str, int flags )
179{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300180 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700181 Reset();
182 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300183 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 _start = new char[ len+1 ];
185 memcpy( _start, str, len+1 );
186 _end = _start + len;
187 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800188}
189
190
191char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700193 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400195 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 char endChar = *endTag;
197 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // Inner loop of text parsing.
200 while ( *p ) {
201 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
202 Set( start, p, strFlags );
203 return p + length;
204 }
205 ++p;
206 }
207 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800208}
209
210
211char* StrPair::ParseName( char* p )
212{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400213 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700214 return 0;
215 }
JayXonee525db2014-12-24 04:01:42 -0500216 if ( !XMLUtil::IsNameStartChar( *p ) ) {
217 return 0;
218 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800219
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500221 ++p;
222 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700223 ++p;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
JayXonee525db2014-12-24 04:01:42 -0500226 Set( start, p, 0 );
227 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800228}
229
230
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700231void StrPair::CollapseWhitespace()
232{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400233 // Adjusting _start would cause undefined behavior on delete[]
234 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700235 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700236 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300238 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700239 char* p = _start; // the read pointer
240 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700241
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 while( *p ) {
243 if ( XMLUtil::IsWhiteSpace( *p )) {
244 p = XMLUtil::SkipWhiteSpace( p );
245 if ( *p == 0 ) {
246 break; // don't write to q; this trims the trailing space.
247 }
248 *q = ' ';
249 ++q;
250 }
251 *q = *p;
252 ++q;
253 ++p;
254 }
255 *q = 0;
256 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700257}
258
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800259
Lee Thomasone4422302012-01-20 17:59:50 -0800260const char* StrPair::GetStr()
261{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300262 TIXMLASSERT( _start );
263 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 if ( _flags & NEEDS_FLUSH ) {
265 *_end = 0;
266 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800267
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 if ( _flags ) {
269 char* p = _start; // the read pointer
270 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800271
Lee Thomason120b3a62012-10-12 10:06:59 -0700272 while( p < _end ) {
273 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700274 // CR-LF pair becomes LF
275 // CR alone becomes LF
276 // LF-CR becomes LF
277 if ( *(p+1) == LF ) {
278 p += 2;
279 }
280 else {
281 ++p;
282 }
283 *q++ = LF;
284 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700285 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700286 if ( *(p+1) == CR ) {
287 p += 2;
288 }
289 else {
290 ++p;
291 }
292 *q++ = LF;
293 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700294 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 // Entities handled by tinyXML2:
296 // - special entities in the entity table [in/out]
297 // - numeric character reference [in]
298 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800299
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400301 const int buflen = 10;
302 char buf[buflen] = { 0 };
303 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300304 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
305 if ( adjusted == 0 ) {
306 *q = *p;
307 ++p;
308 ++q;
309 }
310 else {
311 TIXMLASSERT( 0 <= len && len <= buflen );
312 TIXMLASSERT( q + len <= adjusted );
313 p = adjusted;
314 memcpy( q, buf, len );
315 q += len;
316 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700317 }
318 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300319 bool entityFound = false;
320 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400321 const Entity& entity = entities[i];
322 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
323 && *( p + entity.length + 1 ) == ';' ) {
324 // Found an entity - convert.
325 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400327 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 break;
330 }
331 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300332 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 // fixme: treat as error?
334 ++p;
335 ++q;
336 }
337 }
338 }
339 else {
340 *q = *p;
341 ++p;
342 ++q;
343 }
344 }
345 *q = 0;
346 }
347 // The loop below has plenty going on, and this
348 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300349 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700350 CollapseWhitespace();
351 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700352 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300354 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700355 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800356}
357
Lee Thomason2c85a712012-01-31 08:24:24 -0800358
Lee Thomasone4422302012-01-20 17:59:50 -0800359
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800360
Lee Thomason56bdd022012-02-09 18:16:58 -0800361// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800362
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800363const char* XMLUtil::ReadBOM( const char* p, bool* bom )
364{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300365 TIXMLASSERT( p );
366 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 *bom = false;
368 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
369 // Check for BOM:
370 if ( *(pu+0) == TIXML_UTF_LEAD_0
371 && *(pu+1) == TIXML_UTF_LEAD_1
372 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
373 *bom = true;
374 p += 3;
375 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300376 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800378}
379
380
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 const unsigned long BYTE_MASK = 0xBF;
384 const unsigned long BYTE_MARK = 0x80;
385 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 if (input < 0x80) {
388 *length = 1;
389 }
390 else if ( input < 0x800 ) {
391 *length = 2;
392 }
393 else if ( input < 0x10000 ) {
394 *length = 3;
395 }
396 else if ( input < 0x200000 ) {
397 *length = 4;
398 }
399 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300400 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700401 return;
402 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 // Scary scary fall throughs.
407 switch (*length) {
408 case 4:
409 --output;
410 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
411 input >>= 6;
412 case 3:
413 --output;
414 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
415 input >>= 6;
416 case 2:
417 --output;
418 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
419 input >>= 6;
420 case 1:
421 --output;
422 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100423 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300424 default:
425 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427}
428
429
430const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700432 // Presume an entity, and pull it out.
433 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800434
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 if ( *(p+1) == '#' && *(p+2) ) {
436 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300437 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 ptrdiff_t delta = 0;
439 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800440 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800441
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 if ( *(p+2) == 'x' ) {
443 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300444 const char* q = p+3;
445 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 return 0;
447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448
Lee Thomason7e67bc82015-01-12 14:05:12 -0800449 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800450
Dmitry-Me9f56e122015-01-12 10:07:54 +0300451 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 return 0;
453 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800454 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 delta = q-p;
457 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700460 unsigned int digit = 0;
461
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300463 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 }
465 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300466 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 }
468 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300469 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 }
471 else {
472 return 0;
473 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100474 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300475 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
476 const unsigned int digitScaled = mult * digit;
477 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
478 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300479 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 mult *= 16;
481 --q;
482 }
483 }
484 else {
485 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300486 const char* q = p+2;
487 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 return 0;
489 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800490
Lee Thomason7e67bc82015-01-12 14:05:12 -0800491 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800492
Dmitry-Me9f56e122015-01-12 10:07:54 +0300493 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 return 0;
495 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800496 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800497
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700498 delta = q-p;
499 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 while ( *q != '#' ) {
502 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300503 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100504 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300505 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
506 const unsigned int digitScaled = mult * digit;
507 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
508 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 }
510 else {
511 return 0;
512 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300513 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 mult *= 10;
515 --q;
516 }
517 }
518 // convert the UCS to UTF-8
519 ConvertUTF32ToUTF8( ucs, value, length );
520 return p + delta + 1;
521 }
522 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800524
525
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700526void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700529}
530
531
532void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700535}
536
537
538void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700541}
542
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800543/*
544 ToStr() of a number is a very tricky topic.
545 https://github.com/leethomason/tinyxml2/issues/106
546*/
Lee Thomason21be8822012-07-15 17:27:22 -0700547void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
548{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800549 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
554{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800555 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
Lee Thomason51c12712016-06-04 20:18:49 -0700559void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
560{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700561 // horrible syntax trick to make the compiler happy about %lld
562 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700563}
564
565
Lee Thomason21be8822012-07-15 17:27:22 -0700566bool XMLUtil::ToInt( const char* str, int* value )
567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
569 return true;
570 }
571 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700572}
573
574bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
577 return true;
578 }
579 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700580}
581
582bool XMLUtil::ToBool( const char* str, bool* value )
583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 int ival = 0;
585 if ( ToInt( str, &ival )) {
586 *value = (ival==0) ? false : true;
587 return true;
588 }
589 if ( StringEqual( str, "true" ) ) {
590 *value = true;
591 return true;
592 }
593 else if ( StringEqual( str, "false" ) ) {
594 *value = false;
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600
601bool XMLUtil::ToFloat( const char* str, float* value )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
604 return true;
605 }
606 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700607}
608
Lee Thomason51c12712016-06-04 20:18:49 -0700609
Lee Thomason21be8822012-07-15 17:27:22 -0700610bool XMLUtil::ToDouble( const char* str, double* value )
611{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700612 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
613 return true;
614 }
615 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700616}
617
618
Lee Thomason51c12712016-06-04 20:18:49 -0700619bool XMLUtil::ToInt64(const char* str, int64_t* value)
620{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700621 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
622 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
623 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700624 return true;
625 }
626 return false;
627}
628
629
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700630char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800631{
Dmitry-Me02384662015-03-03 16:02:13 +0300632 TIXMLASSERT( node );
633 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400634 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300636 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300637 *node = 0;
638 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 return p;
640 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641
Dmitry-Me962083b2015-05-26 11:38:30 +0300642 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 static const char* xmlHeader = { "<?" };
644 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300646 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800648
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 static const int xmlHeaderLen = 2;
650 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300652 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
656 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400657 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300659 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
661 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 p += xmlHeaderLen;
663 }
664 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300665 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 returnNode = new (_commentPool.Alloc()) XMLComment( this );
667 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 p += commentHeaderLen;
669 }
670 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300671 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 p += cdataHeaderLen;
676 text->SetCData( true );
677 }
678 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300679 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
681 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 p += dtdHeaderLen;
683 }
684 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300685 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 returnNode = new (_elementPool.Alloc()) XMLElement( this );
687 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += elementHeaderLen;
689 }
690 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300691 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 returnNode = new (_textPool.Alloc()) XMLText( this );
693 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p = start; // Back it up, all the text counts.
695 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800696
Dmitry-Me02384662015-03-03 16:02:13 +0300697 TIXMLASSERT( returnNode );
698 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 *node = returnNode;
700 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701}
702
703
Lee Thomason751da522012-02-10 08:50:51 -0800704bool XMLDocument::Accept( XMLVisitor* visitor ) const
705{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300706 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 if ( visitor->VisitEnter( *this ) ) {
708 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
709 if ( !node->Accept( visitor ) ) {
710 break;
711 }
712 }
713 }
714 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800715}
Lee Thomason56bdd022012-02-09 18:16:58 -0800716
717
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718// --------- XMLNode ----------- //
719
720XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 _document( doc ),
722 _parent( 0 ),
723 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200724 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700725 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200726 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800727{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728}
729
730
731XMLNode::~XMLNode()
732{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 if ( _parent ) {
735 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800737}
738
Michael Daumling21626882013-10-22 17:03:37 +0200739const char* XMLNode::Value() const
740{
Lee Thomason85492022015-05-22 11:07:45 -0700741 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530742 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530743 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200744 return _value.GetStr();
745}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800746
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800747void XMLNode::SetValue( const char* str, bool staticMem )
748{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 }
752 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800755}
756
757
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800758void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800759{
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300761 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300762 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700765
Dmitry-Mee3225b12014-09-03 11:03:11 +0400766 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800769}
770
771
772void XMLNode::Unlink( XMLNode* child )
773{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300774 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300775 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300776 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 if ( child == _firstChild ) {
778 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( child == _lastChild ) {
781 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
Lee Thomasond923c672012-01-23 08:44:25 -0800783
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 if ( child->_prev ) {
785 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 if ( child->_next ) {
788 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700789 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700790 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800791}
792
793
U-Stream\Leeae25a442012-02-17 17:48:16 -0800794void XMLNode::DeleteChild( XMLNode* node )
795{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300796 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300797 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100799 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400800 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800801}
802
803
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800804XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
805{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300806 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300807 if ( addThis->_document != _document ) {
808 TIXMLASSERT( false );
809 return 0;
810 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800811 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700812
Lee Thomason624d43f2012-10-12 10:58:48 -0700813 if ( _lastChild ) {
814 TIXMLASSERT( _firstChild );
815 TIXMLASSERT( _lastChild->_next == 0 );
816 _lastChild->_next = addThis;
817 addThis->_prev = _lastChild;
818 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800819
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
822 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 TIXMLASSERT( _firstChild == 0 );
824 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800825
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 addThis->_prev = 0;
827 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800831}
832
833
Lee Thomason1ff38e02012-02-14 18:18:16 -0800834XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
835{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300836 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300837 if ( addThis->_document != _document ) {
838 TIXMLASSERT( false );
839 return 0;
840 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800841 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700842
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 if ( _firstChild ) {
844 TIXMLASSERT( _lastChild );
845 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 _firstChild->_prev = addThis;
848 addThis->_next = _firstChild;
849 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800850
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 }
853 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( _lastChild == 0 );
855 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_prev = 0;
858 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400861 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800862}
863
864
865XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
866{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300867 TIXMLASSERT( addThis );
868 if ( addThis->_document != _document ) {
869 TIXMLASSERT( false );
870 return 0;
871 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700872
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700874
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300876 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 return 0;
878 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800879
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 // The last node or the only node.
882 return InsertEndChild( addThis );
883 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800884 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 addThis->_prev = afterThis;
886 addThis->_next = afterThis->_next;
887 afterThis->_next->_prev = addThis;
888 afterThis->_next = addThis;
889 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800891}
892
893
894
895
Dmitry-Me886ad972015-07-22 11:00:51 +0300896const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800897{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300898 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
899 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700900 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300901 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 return element;
903 }
904 }
905 }
906 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800907}
908
909
Dmitry-Me886ad972015-07-22 11:00:51 +0300910const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800911{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300912 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
913 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300915 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return element;
917 }
918 }
919 }
920 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800921}
922
923
Dmitry-Me886ad972015-07-22 11:00:51 +0300924const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800925{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300926 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400927 const XMLElement* element = node->ToElement();
928 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300929 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400930 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 }
933 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934}
935
936
Dmitry-Me886ad972015-07-22 11:00:51 +0300937const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300939 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400940 const XMLElement* element = node->ToElement();
941 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300942 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400943 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 }
946 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947}
948
949
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800950char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 // This is a recursive method, but thinking about it "at the current level"
953 // it is a pretty simple flat list:
954 // <foo/>
955 // <!-- comment -->
956 //
957 // With a special case:
958 // <foo>
959 // </foo>
960 // <!-- comment -->
961 //
962 // Where the closing element (/foo) *must* be the next thing after the opening
963 // element, and the names must match. BUT the tricky bit is that the closing
964 // element will be read by the child.
965 //
966 // 'endTag' is the end tag for this node, it is returned by a call to a child.
967 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 while( p && *p ) {
970 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800971
Lee Thomason624d43f2012-10-12 10:58:48 -0700972 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300973 if ( node == 0 ) {
974 break;
975 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 StrPair endTag;
978 p = node->ParseDeep( p, &endTag );
979 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400980 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 if ( !_document->Error() ) {
982 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 }
984 break;
985 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800986
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530987 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530988 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530989 // A declaration can only be the first child of a document.
990 // Set error, if document already has children.
991 if ( !_document->NoChildren() ) {
992 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
993 DeleteNode( decl );
994 break;
995 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530996 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530997
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400998 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001000 // We read the end tag. Return it to the parent.
1001 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1002 if ( parentEnd ) {
1003 ele->_value.TransferTo( parentEnd );
1004 }
1005 node->_memPool->SetTracked(); // created and then immediately deleted.
1006 DeleteNode( node );
1007 return p;
1008 }
1009
1010 // Handle an end tag returned to this level.
1011 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001012 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001013 if ( endTag.Empty() ) {
1014 if ( ele->ClosingType() == XMLElement::OPEN ) {
1015 mismatch = true;
1016 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001018 else {
1019 if ( ele->ClosingType() != XMLElement::OPEN ) {
1020 mismatch = true;
1021 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001022 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001023 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 }
1025 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001026 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001027 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001028 DeleteNode( node );
1029 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001030 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 }
JayXondbfdd8f2014-12-12 20:07:14 -05001032 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 }
1034 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001035}
1036
Dmitry-Mee3225b12014-09-03 11:03:11 +04001037void XMLNode::DeleteNode( XMLNode* node )
1038{
1039 if ( node == 0 ) {
1040 return;
1041 }
1042 MemPool* pool = node->_memPool;
1043 node->~XMLNode();
1044 pool->Free( node );
1045}
1046
Lee Thomason3cebdc42015-01-05 17:16:28 -08001047void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001048{
1049 TIXMLASSERT( insertThis );
1050 TIXMLASSERT( insertThis->_document == _document );
1051
1052 if ( insertThis->_parent )
1053 insertThis->_parent->Unlink( insertThis );
1054 else
1055 insertThis->_memPool->SetTracked();
1056}
1057
Lee Thomason5492a1c2012-01-23 15:32:10 -08001058// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001059char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001060{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 const char* start = p;
1062 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001063 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001065 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 return p;
1068 }
1069 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1071 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001072 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001074
Lee Thomason624d43f2012-10-12 10:58:48 -07001075 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 if ( p && *p ) {
1077 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001078 }
1079 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001080 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 }
1082 }
1083 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001084}
1085
1086
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001087XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001090 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 }
1092 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1093 text->SetCData( this->CData() );
1094 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095}
1096
1097
1098bool XMLText::ShallowEqual( const XMLNode* compare ) const
1099{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001100 const XMLText* text = compare->ToText();
1101 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
Lee Thomason56bdd022012-02-09 18:16:58 -08001105bool XMLText::Accept( XMLVisitor* visitor ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001109}
1110
1111
Lee Thomason3f57d272012-01-11 15:30:03 -08001112// --------- XMLComment ---------- //
1113
Lee Thomasone4422302012-01-20 17:59:50 -08001114XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001115{
1116}
1117
1118
Lee Thomasonce0763e2012-01-11 15:43:54 -08001119XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001120{
Lee Thomason3f57d272012-01-11 15:30:03 -08001121}
1122
1123
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001124char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 // Comment parses as text.
1127 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001130 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 }
1132 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001133}
1134
1135
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001136XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 }
1141 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1142 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001143}
1144
1145
1146bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1147{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001148 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001149 const XMLComment* comment = compare->ToComment();
1150 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001151}
1152
1153
Lee Thomason751da522012-02-10 08:50:51 -08001154bool XMLComment::Accept( XMLVisitor* visitor ) const
1155{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001156 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001158}
Lee Thomason56bdd022012-02-09 18:16:58 -08001159
1160
Lee Thomason50f97b22012-02-11 16:33:40 -08001161// --------- XMLDeclaration ---------- //
1162
1163XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1164{
1165}
1166
1167
1168XMLDeclaration::~XMLDeclaration()
1169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001171}
1172
1173
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001174char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 // Declaration parses as text.
1177 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001178 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001180 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 }
1182 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001183}
1184
1185
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001186XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 }
1191 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1192 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001193}
1194
1195
1196bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1197{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001198 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001199 const XMLDeclaration* declaration = compare->ToDeclaration();
1200 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001201}
1202
1203
1204
Lee Thomason50f97b22012-02-11 16:33:40 -08001205bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1206{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001207 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001209}
1210
1211// --------- XMLUnknown ---------- //
1212
1213XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1214{
1215}
1216
1217
1218XMLUnknown::~XMLUnknown()
1219{
1220}
1221
1222
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001223char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 // Unknown parses as text.
1226 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001227
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 }
1232 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001233}
1234
1235
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001236XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 }
1241 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1242 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001243}
1244
1245
1246bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1247{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001248 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001249 const XMLUnknown* unknown = compare->ToUnknown();
1250 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001251}
1252
1253
Lee Thomason50f97b22012-02-11 16:33:40 -08001254bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1255{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001256 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001258}
1259
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001260// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001261
1262const char* XMLAttribute::Name() const
1263{
1264 return _name.GetStr();
1265}
1266
1267const char* XMLAttribute::Value() const
1268{
1269 return _value.GetStr();
1270}
1271
Lee Thomason6f381b72012-03-02 12:59:39 -08001272char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 if ( !p || !*p ) {
1277 return 0;
1278 }
Lee Thomason22aead12012-01-23 13:29:35 -08001279
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 // Skip white space before =
1281 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001282 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 return 0;
1284 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001285
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 ++p; // move up to opening quote
1287 p = XMLUtil::SkipWhiteSpace( p );
1288 if ( *p != '\"' && *p != '\'' ) {
1289 return 0;
1290 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001291
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 char endTag[2] = { *p, 0 };
1293 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001294
Lee Thomason624d43f2012-10-12 10:58:48 -07001295 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001297}
1298
1299
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001300void XMLAttribute::SetName( const char* n )
1301{
Lee Thomason624d43f2012-10-12 10:58:48 -07001302 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001303}
1304
1305
Lee Thomason2fa81722012-11-09 12:37:46 -08001306XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001309 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 }
1311 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001312}
1313
1314
Lee Thomason2fa81722012-11-09 12:37:46 -08001315XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001318 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 }
1320 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001321}
1322
1323
Lee Thomason51c12712016-06-04 20:18:49 -07001324XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1325{
1326 if (XMLUtil::ToInt64(Value(), value)) {
1327 return XML_SUCCESS;
1328 }
1329 return XML_WRONG_ATTRIBUTE_TYPE;
1330}
1331
1332
Lee Thomason2fa81722012-11-09 12:37:46 -08001333XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001336 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 }
1338 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001339}
1340
1341
Lee Thomason2fa81722012-11-09 12:37:46 -08001342XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001345 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001348}
1349
1350
Lee Thomason2fa81722012-11-09 12:37:46 -08001351XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001354 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 }
1356 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001357}
1358
1359
1360void XMLAttribute::SetAttribute( const char* v )
1361{
Lee Thomason624d43f2012-10-12 10:58:48 -07001362 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001363}
1364
1365
Lee Thomason1ff38e02012-02-14 18:18:16 -08001366void XMLAttribute::SetAttribute( int v )
1367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 char buf[BUF_SIZE];
1369 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001370 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001371}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001372
1373
1374void XMLAttribute::SetAttribute( unsigned v )
1375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 char buf[BUF_SIZE];
1377 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001378 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001379}
1380
1381
Lee Thomason51c12712016-06-04 20:18:49 -07001382void XMLAttribute::SetAttribute(int64_t v)
1383{
1384 char buf[BUF_SIZE];
1385 XMLUtil::ToStr(v, buf, BUF_SIZE);
1386 _value.SetStr(buf);
1387}
1388
1389
1390
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001391void XMLAttribute::SetAttribute( bool v )
1392{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 char buf[BUF_SIZE];
1394 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001396}
1397
1398void XMLAttribute::SetAttribute( double v )
1399{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 char buf[BUF_SIZE];
1401 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001402 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001403}
1404
1405void XMLAttribute::SetAttribute( float v )
1406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 char buf[BUF_SIZE];
1408 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001409 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001410}
1411
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001412
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001413// --------- XMLElement ---------- //
1414XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 _closingType( 0 ),
1416 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001417{
1418}
1419
1420
1421XMLElement::~XMLElement()
1422{
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 while( _rootAttribute ) {
1424 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001425 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001428}
1429
1430
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001431const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1432{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001433 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1435 return a;
1436 }
1437 }
1438 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439}
1440
1441
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001442const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 const XMLAttribute* a = FindAttribute( name );
1445 if ( !a ) {
1446 return 0;
1447 }
1448 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1449 return a->Value();
1450 }
1451 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001452}
1453
1454
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001455const char* XMLElement::GetText() const
1456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001458 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 }
1460 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001461}
1462
1463
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001464void XMLElement::SetText( const char* inText )
1465{
Uli Kusterer869bb592014-01-21 01:36:16 +01001466 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001467 FirstChild()->SetValue( inText );
1468 else {
1469 XMLText* theText = GetDocument()->NewText( inText );
1470 InsertFirstChild( theText );
1471 }
1472}
1473
Lee Thomason5bb2d802014-01-24 10:42:57 -08001474
1475void XMLElement::SetText( int v )
1476{
1477 char buf[BUF_SIZE];
1478 XMLUtil::ToStr( v, buf, BUF_SIZE );
1479 SetText( buf );
1480}
1481
1482
1483void XMLElement::SetText( unsigned v )
1484{
1485 char buf[BUF_SIZE];
1486 XMLUtil::ToStr( v, buf, BUF_SIZE );
1487 SetText( buf );
1488}
1489
1490
Lee Thomason51c12712016-06-04 20:18:49 -07001491void XMLElement::SetText(int64_t v)
1492{
1493 char buf[BUF_SIZE];
1494 XMLUtil::ToStr(v, buf, BUF_SIZE);
1495 SetText(buf);
1496}
1497
1498
1499void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001500{
1501 char buf[BUF_SIZE];
1502 XMLUtil::ToStr( v, buf, BUF_SIZE );
1503 SetText( buf );
1504}
1505
1506
1507void XMLElement::SetText( float v )
1508{
1509 char buf[BUF_SIZE];
1510 XMLUtil::ToStr( v, buf, BUF_SIZE );
1511 SetText( buf );
1512}
1513
1514
1515void XMLElement::SetText( double v )
1516{
1517 char buf[BUF_SIZE];
1518 XMLUtil::ToStr( v, buf, BUF_SIZE );
1519 SetText( buf );
1520}
1521
1522
MortenMacFly4ee49f12013-01-14 20:03:14 +01001523XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001526 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001527 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 return XML_SUCCESS;
1529 }
1530 return XML_CAN_NOT_CONVERT_TEXT;
1531 }
1532 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001533}
1534
1535
MortenMacFly4ee49f12013-01-14 20:03:14 +01001536XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001539 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001540 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return XML_SUCCESS;
1542 }
1543 return XML_CAN_NOT_CONVERT_TEXT;
1544 }
1545 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001546}
1547
1548
Lee Thomason51c12712016-06-04 20:18:49 -07001549XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1550{
1551 if (FirstChild() && FirstChild()->ToText()) {
1552 const char* t = FirstChild()->Value();
1553 if (XMLUtil::ToInt64(t, ival)) {
1554 return XML_SUCCESS;
1555 }
1556 return XML_CAN_NOT_CONVERT_TEXT;
1557 }
1558 return XML_NO_TEXT_NODE;
1559}
1560
1561
MortenMacFly4ee49f12013-01-14 20:03:14 +01001562XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001563{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001565 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001566 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 return XML_SUCCESS;
1568 }
1569 return XML_CAN_NOT_CONVERT_TEXT;
1570 }
1571 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001572}
1573
1574
MortenMacFly4ee49f12013-01-14 20:03:14 +01001575XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001578 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001579 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 return XML_SUCCESS;
1581 }
1582 return XML_CAN_NOT_CONVERT_TEXT;
1583 }
1584 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001585}
1586
1587
MortenMacFly4ee49f12013-01-14 20:03:14 +01001588XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001591 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001592 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 return XML_SUCCESS;
1594 }
1595 return XML_CAN_NOT_CONVERT_TEXT;
1596 }
1597 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001598}
1599
1600
1601
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001602XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 XMLAttribute* last = 0;
1605 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1610 break;
1611 }
1612 }
1613 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001614 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1616 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 }
1620 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 }
1623 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001624 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 }
1626 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001627}
1628
1629
U-Stream\Leeae25a442012-02-17 17:48:16 -08001630void XMLElement::DeleteAttribute( const char* name )
1631{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001633 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1635 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001636 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 }
1638 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001639 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001641 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 break;
1643 }
1644 prev = a;
1645 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001646}
1647
1648
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001649char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 const char* start = p;
1652 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001653
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 // Read the attributes.
1655 while( p ) {
1656 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001657 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 return 0;
1660 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001661
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001663 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001664 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001665 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1666 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001667 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001668
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001671 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 return 0;
1674 }
1675 // There is a minor bug here: if the attribute in the source xml
1676 // document is duplicated, it will not be detected and the
1677 // attribute will be doubly added. However, tracking the 'prevAttribute'
1678 // avoids re-scanning the attribute list. Preferring performance for
1679 // now, may reconsider in the future.
1680 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 }
1683 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 }
1686 prevAttribute = attrib;
1687 }
1688 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 else if ( *p == '>' ) {
1690 ++p;
1691 break;
1692 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001693 // end of the tag
1694 else if ( *p == '/' && *(p+1) == '>' ) {
1695 _closingType = CLOSED;
1696 return p+2; // done; sealed element.
1697 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001699 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 return 0;
1701 }
1702 }
1703 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001704}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001705
Dmitry-Mee3225b12014-09-03 11:03:11 +04001706void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1707{
1708 if ( attribute == 0 ) {
1709 return;
1710 }
1711 MemPool* pool = attribute->_memPool;
1712 attribute->~XMLAttribute();
1713 pool->Free( attribute );
1714}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001715
Lee Thomason67d61312012-01-24 16:01:51 -08001716//
1717// <ele></ele>
1718// <ele>foo<b>bar</b></ele>
1719//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001720char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 // Read the element name.
1723 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001724
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 // The closing element is the </element> form. It is
1726 // parsed just like a regular element then deleted from
1727 // the DOM.
1728 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 ++p;
1731 }
Lee Thomason67d61312012-01-24 16:01:51 -08001732
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 p = _value.ParseName( p );
1734 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 return 0;
1736 }
Lee Thomason67d61312012-01-24 16:01:51 -08001737
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 return p;
1741 }
Lee Thomason67d61312012-01-24 16:01:51 -08001742
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 p = XMLNode::ParseDeep( p, strPair );
1744 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001745}
1746
1747
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001748
1749XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 }
1754 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1755 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1756 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1757 }
1758 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001759}
1760
1761
1762bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1763{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001764 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001766 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001767
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 const XMLAttribute* a=FirstAttribute();
1769 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001770
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 while ( a && b ) {
1772 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1773 return false;
1774 }
1775 a = a->Next();
1776 b = b->Next();
1777 }
1778 if ( a || b ) {
1779 // different count
1780 return false;
1781 }
1782 return true;
1783 }
1784 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001785}
1786
1787
Lee Thomason751da522012-02-10 08:50:51 -08001788bool XMLElement::Accept( XMLVisitor* visitor ) const
1789{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001790 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1793 if ( !node->Accept( visitor ) ) {
1794 break;
1795 }
1796 }
1797 }
1798 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001799}
Lee Thomason56bdd022012-02-09 18:16:58 -08001800
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001801
Lee Thomason3f57d272012-01-11 15:30:03 -08001802// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001803
1804// Warning: List must match 'enum XMLError'
1805const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1806 "XML_SUCCESS",
1807 "XML_NO_ATTRIBUTE",
1808 "XML_WRONG_ATTRIBUTE_TYPE",
1809 "XML_ERROR_FILE_NOT_FOUND",
1810 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1811 "XML_ERROR_FILE_READ_ERROR",
1812 "XML_ERROR_ELEMENT_MISMATCH",
1813 "XML_ERROR_PARSING_ELEMENT",
1814 "XML_ERROR_PARSING_ATTRIBUTE",
1815 "XML_ERROR_IDENTIFYING_TAG",
1816 "XML_ERROR_PARSING_TEXT",
1817 "XML_ERROR_PARSING_CDATA",
1818 "XML_ERROR_PARSING_COMMENT",
1819 "XML_ERROR_PARSING_DECLARATION",
1820 "XML_ERROR_PARSING_UNKNOWN",
1821 "XML_ERROR_EMPTY_DOCUMENT",
1822 "XML_ERROR_MISMATCHED_ELEMENT",
1823 "XML_ERROR_PARSING",
1824 "XML_CAN_NOT_CONVERT_TEXT",
1825 "XML_NO_TEXT_NODE"
1826};
1827
1828
Lee Thomason624d43f2012-10-12 10:58:48 -07001829XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _writeBOM( false ),
1832 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001833 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 _whitespace( whitespace ),
1835 _errorStr1( 0 ),
1836 _errorStr2( 0 ),
1837 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001838{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001839 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1840 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001841}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001842
1843
Lee Thomason3f57d272012-01-11 15:30:03 -08001844XMLDocument::~XMLDocument()
1845{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001846 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001847}
1848
1849
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001850void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001851{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001852 DeleteChildren();
1853
Dmitry-Meab37df82014-11-28 12:08:36 +03001854#ifdef DEBUG
1855 const bool hadError = Error();
1856#endif
Lee Thomason85536252016-06-04 19:10:53 -07001857 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 _errorStr1 = 0;
1859 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001860
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 delete [] _charBuffer;
1862 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001863
1864#if 0
1865 _textPool.Trace( "text" );
1866 _elementPool.Trace( "element" );
1867 _commentPool.Trace( "comment" );
1868 _attributePool.Trace( "attribute" );
1869#endif
1870
1871#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001872 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001873 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1874 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1875 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1876 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1877 }
1878#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001879}
1880
Lee Thomason3f57d272012-01-11 15:30:03 -08001881
Lee Thomason2c85a712012-01-31 08:24:24 -08001882XMLElement* XMLDocument::NewElement( const char* name )
1883{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001884 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1886 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 ele->SetName( name );
1888 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001889}
1890
1891
Lee Thomason1ff38e02012-02-14 18:18:16 -08001892XMLComment* XMLDocument::NewComment( const char* str )
1893{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001894 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1896 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 comment->SetValue( str );
1898 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001899}
1900
1901
1902XMLText* XMLDocument::NewText( const char* str )
1903{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001904 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1906 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 text->SetValue( str );
1908 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001909}
1910
1911
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001912XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1913{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001914 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1916 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1918 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001919}
1920
1921
1922XMLUnknown* XMLDocument::NewUnknown( const char* str )
1923{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001924 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1926 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 unk->SetValue( str );
1928 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001929}
1930
Dmitry-Me01578db2014-08-19 10:18:48 +04001931static FILE* callfopen( const char* filepath, const char* mode )
1932{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001933 TIXMLASSERT( filepath );
1934 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001935#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1936 FILE* fp = 0;
1937 errno_t err = fopen_s( &fp, filepath, mode );
1938 if ( err ) {
1939 return 0;
1940 }
1941#else
1942 FILE* fp = fopen( filepath, mode );
1943#endif
1944 return fp;
1945}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001946
1947void XMLDocument::DeleteNode( XMLNode* node ) {
1948 TIXMLASSERT( node );
1949 TIXMLASSERT(node->_document == this );
1950 if (node->_parent) {
1951 node->_parent->DeleteChild( node );
1952 }
1953 else {
1954 // Isn't in the tree.
1955 // Use the parent delete.
1956 // Also, we need to mark it tracked: we 'know'
1957 // it was never used.
1958 node->_memPool->SetTracked();
1959 // Call the static XMLNode version:
1960 XMLNode::DeleteNode(node);
1961 }
1962}
1963
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001964
Lee Thomason2fa81722012-11-09 12:37:46 -08001965XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001966{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001967 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001968 FILE* fp = callfopen( filename, "rb" );
1969 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 }
1973 LoadFile( fp );
1974 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001976}
1977
Dmitry-Me901fed52015-09-25 10:29:51 +03001978// This is likely overengineered template art to have a check that unsigned long value incremented
1979// by one still fits into size_t. If size_t type is larger than unsigned long type
1980// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1981// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1982// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1983// types sizes relate to each other.
1984template
1985<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1986struct LongFitsIntoSizeTMinusOne {
1987 static bool Fits( unsigned long value )
1988 {
1989 return value < (size_t)-1;
1990 }
1991};
1992
1993template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001994struct LongFitsIntoSizeTMinusOne<false> {
1995 static bool Fits( unsigned long )
1996 {
1997 return true;
1998 }
1999};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002000
Lee Thomason2fa81722012-11-09 12:37:46 -08002001XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002002{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002003 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002004
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002005 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002006 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002007 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2008 return _errorID;
2009 }
2010
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002012 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002014 if ( filelength == -1L ) {
2015 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2016 return _errorID;
2017 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002018 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002019
Dmitry-Me901fed52015-09-25 10:29:51 +03002020 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002021 // Cannot handle files which won't fit in buffer together with null terminator
2022 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2023 return _errorID;
2024 }
2025
Dmitry-Me72801b82015-05-07 09:41:39 +03002026 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002027 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002030
Dmitry-Me72801b82015-05-07 09:41:39 +03002031 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002032 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 _charBuffer = new char[size+1];
2034 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 if ( read != size ) {
2036 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002039
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002041
Dmitry-Me97476b72015-01-01 16:15:57 +03002042 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002043 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002044}
2045
2046
Lee Thomason2fa81722012-11-09 12:37:46 -08002047XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002048{
Dmitry-Me01578db2014-08-19 10:18:48 +04002049 FILE* fp = callfopen( filename, "w" );
2050 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 }
2054 SaveFile(fp, compact);
2055 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002057}
2058
2059
Lee Thomason2fa81722012-11-09 12:37:46 -08002060XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002061{
Ant Mitchell189198f2015-03-24 16:20:36 +00002062 // Clear any error from the last save, otherwise it will get reported
2063 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002064 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 XMLPrinter stream( fp, compact );
2066 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002068}
2069
Lee Thomason1ff38e02012-02-14 18:18:16 -08002070
Lee Thomason2fa81722012-11-09 12:37:46 -08002071XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002072{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002073 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002074
Lee Thomason82d32002014-02-21 22:47:18 -08002075 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 }
2079 if ( len == (size_t)(-1) ) {
2080 len = strlen( p );
2081 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002082 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _charBuffer = new char[ len+1 ];
2084 memcpy( _charBuffer, p, len );
2085 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002086
Dmitry-Me97476b72015-01-01 16:15:57 +03002087 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002088 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002089 // clean up now essentially dangling memory.
2090 // and the parse fail can put objects in the
2091 // pools that are dead and inaccessible.
2092 DeleteChildren();
2093 _elementPool.Clear();
2094 _attributePool.Clear();
2095 _textPool.Clear();
2096 _commentPool.Clear();
2097 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002098 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002099}
2100
2101
PKEuS1c5f99e2013-07-06 11:28:39 +02002102void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002103{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002104 if ( streamer ) {
2105 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002107 else {
2108 XMLPrinter stdoutStreamer( stdout );
2109 Accept( &stdoutStreamer );
2110 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002111}
2112
2113
Lee Thomason2fa81722012-11-09 12:37:46 -08002114void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002115{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002116 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 _errorID = error;
2118 _errorStr1 = str1;
2119 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002120}
2121
Lee Thomason331596e2014-09-11 14:56:43 -07002122const char* XMLDocument::ErrorName() const
2123{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002124 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002125 const char* errorName = _errorNames[_errorID];
2126 TIXMLASSERT( errorName && errorName[0] );
2127 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002128}
Lee Thomason5cae8972012-01-24 18:03:07 -08002129
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002130void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002131{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002132 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 static const int LEN = 20;
2134 char buf1[LEN] = { 0 };
2135 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002136
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _errorStr1 ) {
2138 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _errorStr2 ) {
2141 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002143
Dmitry-Me2ad43202015-04-16 12:18:58 +03002144 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2145 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2146 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002147 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002148 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002150}
2151
Dmitry-Me97476b72015-01-01 16:15:57 +03002152void XMLDocument::Parse()
2153{
2154 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2155 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002156 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002157 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002158 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002159 if ( !*p ) {
2160 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2161 return;
2162 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002163 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002164}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002165
PKEuS1bfb9542013-08-04 13:51:17 +02002166XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 _elementJustOpened( false ),
2168 _firstElement( true ),
2169 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002170 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _textDepth( -1 ),
2172 _processEntities( true ),
2173 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 _entityFlag[i] = false;
2177 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 }
2179 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002180 const char entityValue = entities[i].value;
2181 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2182 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002184 _restrictedEntityFlag[(unsigned char)'&'] = true;
2185 _restrictedEntityFlag[(unsigned char)'<'] = true;
2186 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002188}
2189
2190
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002191void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002192{
2193 va_list va;
2194 va_start( va, format );
2195
Lee Thomason624d43f2012-10-12 10:58:48 -07002196 if ( _fp ) {
2197 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 }
2199 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002200 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 // Close out and re-start the va-args
2202 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002203 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002205 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002206 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002207 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002209 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002210}
2211
2212
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002213void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 for( int i=0; i<depth; ++i ) {
2216 Print( " " );
2217 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002218}
2219
2220
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002221void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 // Look for runs of bytes between entities to print.
2224 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002225
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002227 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002229 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 // Remember, char is sometimes signed. (How many times has that bitten me?)
2231 if ( *q > 0 && *q < ENTITY_RANGE ) {
2232 // Check for entities. If one is found, flush
2233 // the stream up until the entity, write the
2234 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002235 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002237 const size_t delta = q - p;
2238 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002239 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002240 Print( "%.*s", toPrint, p );
2241 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002243 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 for( int i=0; i<NUM_ENTITIES; ++i ) {
2245 if ( entities[i].value == *q ) {
2246 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002247 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 break;
2249 }
2250 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002251 if ( !entityPatternPrinted ) {
2252 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2253 TIXMLASSERT( false );
2254 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 ++p;
2256 }
2257 }
2258 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002259 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 }
2261 }
2262 // Flush the remaining string. This will be the entire
2263 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002264 TIXMLASSERT( p <= q );
2265 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 Print( "%s", p );
2267 }
Lee Thomason857b8682012-01-25 17:50:25 -08002268}
2269
U-Stream\Leeae25a442012-02-17 17:48:16 -08002270
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002271void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002274 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 -07002275 Print( "%s", bom );
2276 }
2277 if ( writeDec ) {
2278 PushDeclaration( "xml version=\"1.0\"" );
2279 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002280}
2281
2282
Uli Kusterer593a33d2014-02-01 12:48:51 +01002283void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002284{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002285 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002287
Uli Kusterer593a33d2014-02-01 12:48:51 +01002288 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002290 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002291 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002294
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002296 _elementJustOpened = true;
2297 _firstElement = false;
2298 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002299}
2300
2301
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002302void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002303{
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 Print( " %s=\"", name );
2306 PrintString( value, false );
2307 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002308}
2309
2310
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002311void XMLPrinter::PushAttribute( const char* name, int v )
2312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 char buf[BUF_SIZE];
2314 XMLUtil::ToStr( v, buf, BUF_SIZE );
2315 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002316}
2317
2318
2319void XMLPrinter::PushAttribute( const char* name, unsigned v )
2320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002321 char buf[BUF_SIZE];
2322 XMLUtil::ToStr( v, buf, BUF_SIZE );
2323 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002324}
2325
2326
Lee Thomason51c12712016-06-04 20:18:49 -07002327void XMLPrinter::PushAttribute(const char* name, int64_t v)
2328{
2329 char buf[BUF_SIZE];
2330 XMLUtil::ToStr(v, buf, BUF_SIZE);
2331 PushAttribute(name, buf);
2332}
2333
2334
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002335void XMLPrinter::PushAttribute( const char* name, bool v )
2336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 char buf[BUF_SIZE];
2338 XMLUtil::ToStr( v, buf, BUF_SIZE );
2339 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002340}
2341
2342
2343void XMLPrinter::PushAttribute( const char* name, double v )
2344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 char buf[BUF_SIZE];
2346 XMLUtil::ToStr( v, buf, BUF_SIZE );
2347 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002348}
2349
2350
Uli Kustererca412e82014-02-01 13:35:05 +01002351void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002352{
Lee Thomason624d43f2012-10-12 10:58:48 -07002353 --_depth;
2354 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002355
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 Print( "/>" );
2358 }
2359 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002360 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002362 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 }
2364 Print( "</%s>", name );
2365 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002366
Lee Thomason624d43f2012-10-12 10:58:48 -07002367 if ( _textDepth == _depth ) {
2368 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 }
Uli Kustererca412e82014-02-01 13:35:05 +01002370 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 Print( "\n" );
2372 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002374}
2375
2376
Dmitry-Mea092bc12014-12-23 17:57:05 +03002377void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002378{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002379 if ( !_elementJustOpened ) {
2380 return;
2381 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002382 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002384}
2385
2386
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002387void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002388{
Lee Thomason624d43f2012-10-12 10:58:48 -07002389 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002390
Dmitry-Mea092bc12014-12-23 17:57:05 +03002391 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002393 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 }
2395 else {
2396 PrintString( text, true );
2397 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002398}
2399
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002400void XMLPrinter::PushText( int64_t value )
2401{
2402 char buf[BUF_SIZE];
2403 XMLUtil::ToStr( value, buf, BUF_SIZE );
2404 PushText( buf, false );
2405}
2406
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002407void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002409 char buf[BUF_SIZE];
2410 XMLUtil::ToStr( value, buf, BUF_SIZE );
2411 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002412}
2413
2414
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002415void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 char buf[BUF_SIZE];
2418 XMLUtil::ToStr( value, buf, BUF_SIZE );
2419 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002420}
2421
2422
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002423void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 char buf[BUF_SIZE];
2426 XMLUtil::ToStr( value, buf, BUF_SIZE );
2427 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002428}
2429
2430
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002431void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 char buf[BUF_SIZE];
2434 XMLUtil::ToStr( value, buf, BUF_SIZE );
2435 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002436}
2437
2438
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002439void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 char buf[BUF_SIZE];
2442 XMLUtil::ToStr( value, buf, BUF_SIZE );
2443 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002444}
2445
Lee Thomason5cae8972012-01-24 18:03:07 -08002446
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002447void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002448{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002449 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002450 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002452 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002454 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002456}
Lee Thomason751da522012-02-10 08:50:51 -08002457
2458
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002459void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002460{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002461 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002462 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002463 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002464 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002466 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002467 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002468}
2469
2470
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002471void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002472{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002473 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002474 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002476 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002478 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002480}
2481
2482
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002483bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002484{
Lee Thomason624d43f2012-10-12 10:58:48 -07002485 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002486 if ( doc.HasBOM() ) {
2487 PushHeader( true, false );
2488 }
2489 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002490}
2491
2492
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002493bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002494{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002495 const XMLElement* parentElem = 0;
2496 if ( element.Parent() ) {
2497 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002498 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002499 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002500 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 while ( attribute ) {
2502 PushAttribute( attribute->Name(), attribute->Value() );
2503 attribute = attribute->Next();
2504 }
2505 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002506}
2507
2508
Uli Kustererca412e82014-02-01 13:35:05 +01002509bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002510{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002511 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002512 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002513}
2514
2515
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002516bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 PushText( text.Value(), text.CData() );
2519 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002520}
2521
2522
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002523bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 PushComment( comment.Value() );
2526 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002527}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002528
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002529bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 PushDeclaration( declaration.Value() );
2532 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002533}
2534
2535
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002536bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002538 PushUnknown( unknown.Value() );
2539 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002540}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002541
Lee Thomason685b8952012-11-12 13:00:06 -08002542} // namespace tinyxml2
2543