blob: c4ea7cd5e32e8bc445801dd5ea297fd32eb1e6d4 [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.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || 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 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300474 TIXMLASSERT( digit >= 0 && 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';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300504 TIXMLASSERT( digit >= 0 && 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
559bool XMLUtil::ToInt( const char* str, int* value )
560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
562 return true;
563 }
564 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700565}
566
567bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
570 return true;
571 }
572 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700573}
574
575bool XMLUtil::ToBool( const char* str, bool* value )
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 int ival = 0;
578 if ( ToInt( str, &ival )) {
579 *value = (ival==0) ? false : true;
580 return true;
581 }
582 if ( StringEqual( str, "true" ) ) {
583 *value = true;
584 return true;
585 }
586 else if ( StringEqual( str, "false" ) ) {
587 *value = false;
588 return true;
589 }
590 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700591}
592
593
594bool XMLUtil::ToFloat( const char* str, float* value )
595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
597 return true;
598 }
599 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700600}
601
602bool XMLUtil::ToDouble( const char* str, double* value )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
605 return true;
606 }
607 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700608}
609
610
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700611char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800612{
Dmitry-Me02384662015-03-03 16:02:13 +0300613 TIXMLASSERT( node );
614 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400615 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300617 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300618 *node = 0;
619 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 return p;
621 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622
Dmitry-Me962083b2015-05-26 11:38:30 +0300623 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 static const char* xmlHeader = { "<?" };
625 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300627 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800629
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 static const int xmlHeaderLen = 2;
631 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300633 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
637 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400638 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300640 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
642 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 p += xmlHeaderLen;
644 }
645 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300646 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 returnNode = new (_commentPool.Alloc()) XMLComment( this );
648 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 p += commentHeaderLen;
650 }
651 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300652 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 p += cdataHeaderLen;
657 text->SetCData( true );
658 }
659 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300660 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
662 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 p += dtdHeaderLen;
664 }
665 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300666 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 returnNode = new (_elementPool.Alloc()) XMLElement( this );
668 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 p += elementHeaderLen;
670 }
671 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300672 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 returnNode = new (_textPool.Alloc()) XMLText( this );
674 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 p = start; // Back it up, all the text counts.
676 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677
Dmitry-Me02384662015-03-03 16:02:13 +0300678 TIXMLASSERT( returnNode );
679 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 *node = returnNode;
681 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682}
683
684
Lee Thomason751da522012-02-10 08:50:51 -0800685bool XMLDocument::Accept( XMLVisitor* visitor ) const
686{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300687 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 if ( visitor->VisitEnter( *this ) ) {
689 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
690 if ( !node->Accept( visitor ) ) {
691 break;
692 }
693 }
694 }
695 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800696}
Lee Thomason56bdd022012-02-09 18:16:58 -0800697
698
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699// --------- XMLNode ----------- //
700
701XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 _document( doc ),
703 _parent( 0 ),
704 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200705 _prev( 0 ), _next( 0 ),
706 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800708}
709
710
711XMLNode::~XMLNode()
712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700713 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 if ( _parent ) {
715 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800717}
718
Michael Daumling21626882013-10-22 17:03:37 +0200719const char* XMLNode::Value() const
720{
Lee Thomason85492022015-05-22 11:07:45 -0700721 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530722 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530723 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200724 return _value.GetStr();
725}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800726
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800727void XMLNode::SetValue( const char* str, bool staticMem )
728{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
732 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800735}
736
737
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800738void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800739{
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300741 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300742 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700745
Dmitry-Mee3225b12014-09-03 11:03:11 +0400746 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800749}
750
751
752void XMLNode::Unlink( XMLNode* child )
753{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300754 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300755 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300756 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( child == _firstChild ) {
758 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 if ( child == _lastChild ) {
761 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomasond923c672012-01-23 08:44:25 -0800763
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 if ( child->_prev ) {
765 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 if ( child->_next ) {
768 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700770 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800771}
772
773
U-Stream\Leeae25a442012-02-17 17:48:16 -0800774void XMLNode::DeleteChild( XMLNode* node )
775{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300776 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300777 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100779 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400780 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800781}
782
783
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800784XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
785{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300786 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300787 if ( addThis->_document != _document ) {
788 TIXMLASSERT( false );
789 return 0;
790 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800791 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700792
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 if ( _lastChild ) {
794 TIXMLASSERT( _firstChild );
795 TIXMLASSERT( _lastChild->_next == 0 );
796 _lastChild->_next = addThis;
797 addThis->_prev = _lastChild;
798 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800799
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 }
802 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 TIXMLASSERT( _firstChild == 0 );
804 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 addThis->_prev = 0;
807 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800811}
812
813
Lee Thomason1ff38e02012-02-14 18:18:16 -0800814XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
815{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300816 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300817 if ( addThis->_document != _document ) {
818 TIXMLASSERT( false );
819 return 0;
820 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800821 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 if ( _firstChild ) {
824 TIXMLASSERT( _lastChild );
825 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 _firstChild->_prev = addThis;
828 addThis->_next = _firstChild;
829 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
833 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 TIXMLASSERT( _lastChild == 0 );
835 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800836
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 addThis->_prev = 0;
838 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400841 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800842}
843
844
845XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
846{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300847 TIXMLASSERT( addThis );
848 if ( addThis->_document != _document ) {
849 TIXMLASSERT( false );
850 return 0;
851 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700852
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700854
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300856 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 return 0;
858 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 // The last node or the only node.
862 return InsertEndChild( addThis );
863 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800864 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_prev = afterThis;
866 addThis->_next = afterThis->_next;
867 afterThis->_next->_prev = addThis;
868 afterThis->_next = addThis;
869 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800871}
872
873
874
875
Dmitry-Me886ad972015-07-22 11:00:51 +0300876const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800877{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300878 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
879 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300881 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 return element;
883 }
884 }
885 }
886 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800887}
888
889
Dmitry-Me886ad972015-07-22 11:00:51 +0300890const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800891{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300892 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
893 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300895 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 return element;
897 }
898 }
899 }
900 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800901}
902
903
Dmitry-Me886ad972015-07-22 11:00:51 +0300904const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300906 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400907 const XMLElement* element = node->ToElement();
908 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300909 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400910 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 }
913 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800914}
915
916
Dmitry-Me886ad972015-07-22 11:00:51 +0300917const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800918{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300919 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400920 const XMLElement* element = node->ToElement();
921 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300922 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400923 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
925 }
926 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800927}
928
929
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800930char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800931{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 // This is a recursive method, but thinking about it "at the current level"
933 // it is a pretty simple flat list:
934 // <foo/>
935 // <!-- comment -->
936 //
937 // With a special case:
938 // <foo>
939 // </foo>
940 // <!-- comment -->
941 //
942 // Where the closing element (/foo) *must* be the next thing after the opening
943 // element, and the names must match. BUT the tricky bit is that the closing
944 // element will be read by the child.
945 //
946 // 'endTag' is the end tag for this node, it is returned by a call to a child.
947 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800948
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 while( p && *p ) {
950 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800951
Lee Thomason624d43f2012-10-12 10:58:48 -0700952 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300953 if ( node == 0 ) {
954 break;
955 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800956
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 StrPair endTag;
958 p = node->ParseDeep( p, &endTag );
959 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400960 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700961 if ( !_document->Error() ) {
962 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 }
964 break;
965 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530967 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530968 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530969 // A declaration can only be the first child of a document.
970 // Set error, if document already has children.
971 if ( !_document->NoChildren() ) {
972 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
973 DeleteNode( decl );
974 break;
975 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530976 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530977
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400978 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500980 // We read the end tag. Return it to the parent.
981 if ( ele->ClosingType() == XMLElement::CLOSING ) {
982 if ( parentEnd ) {
983 ele->_value.TransferTo( parentEnd );
984 }
985 node->_memPool->SetTracked(); // created and then immediately deleted.
986 DeleteNode( node );
987 return p;
988 }
989
990 // Handle an end tag returned to this level.
991 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400992 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300993 if ( endTag.Empty() ) {
994 if ( ele->ClosingType() == XMLElement::OPEN ) {
995 mismatch = true;
996 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300998 else {
999 if ( ele->ClosingType() != XMLElement::OPEN ) {
1000 mismatch = true;
1001 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001002 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001003 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001006 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001007 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001008 DeleteNode( node );
1009 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001010 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
JayXondbfdd8f2014-12-12 20:07:14 -05001012 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 }
1014 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001015}
1016
Dmitry-Mee3225b12014-09-03 11:03:11 +04001017void XMLNode::DeleteNode( XMLNode* node )
1018{
1019 if ( node == 0 ) {
1020 return;
1021 }
1022 MemPool* pool = node->_memPool;
1023 node->~XMLNode();
1024 pool->Free( node );
1025}
1026
Lee Thomason3cebdc42015-01-05 17:16:28 -08001027void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001028{
1029 TIXMLASSERT( insertThis );
1030 TIXMLASSERT( insertThis->_document == _document );
1031
1032 if ( insertThis->_parent )
1033 insertThis->_parent->Unlink( insertThis );
1034 else
1035 insertThis->_memPool->SetTracked();
1036}
1037
Lee Thomason5492a1c2012-01-23 15:32:10 -08001038// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001039char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 const char* start = p;
1042 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 }
1047 return p;
1048 }
1049 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1051 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001052 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001054
Lee Thomason624d43f2012-10-12 10:58:48 -07001055 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 if ( p && *p ) {
1057 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001058 }
1059 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001060 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 }
1062 }
1063 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001064}
1065
1066
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001067XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 }
1072 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1073 text->SetCData( this->CData() );
1074 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001075}
1076
1077
1078bool XMLText::ShallowEqual( const XMLNode* compare ) const
1079{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001080 const XMLText* text = compare->ToText();
1081 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001082}
1083
1084
Lee Thomason56bdd022012-02-09 18:16:58 -08001085bool XMLText::Accept( XMLVisitor* visitor ) const
1086{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001087 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001089}
1090
1091
Lee Thomason3f57d272012-01-11 15:30:03 -08001092// --------- XMLComment ---------- //
1093
Lee Thomasone4422302012-01-20 17:59:50 -08001094XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001095{
1096}
1097
1098
Lee Thomasonce0763e2012-01-11 15:43:54 -08001099XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001100{
Lee Thomason3f57d272012-01-11 15:30:03 -08001101}
1102
1103
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001104char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001105{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 // Comment parses as text.
1107 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001110 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001113}
1114
1115
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001116XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001119 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1122 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123}
1124
1125
1126bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1127{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001128 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001129 const XMLComment* comment = compare->ToComment();
1130 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
Lee Thomason751da522012-02-10 08:50:51 -08001134bool XMLComment::Accept( XMLVisitor* visitor ) const
1135{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001136 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001138}
Lee Thomason56bdd022012-02-09 18:16:58 -08001139
1140
Lee Thomason50f97b22012-02-11 16:33:40 -08001141// --------- XMLDeclaration ---------- //
1142
1143XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1144{
1145}
1146
1147
1148XMLDeclaration::~XMLDeclaration()
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001151}
1152
1153
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001154char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 // Declaration parses as text.
1157 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 }
1162 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001163}
1164
1165
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001166XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001169 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 }
1171 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1172 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001173}
1174
1175
1176bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1177{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001178 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001179 const XMLDeclaration* declaration = compare->ToDeclaration();
1180 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001181}
1182
1183
1184
Lee Thomason50f97b22012-02-11 16:33:40 -08001185bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1186{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001187 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001189}
1190
1191// --------- XMLUnknown ---------- //
1192
1193XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1194{
1195}
1196
1197
1198XMLUnknown::~XMLUnknown()
1199{
1200}
1201
1202
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001203char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 // Unknown parses as text.
1206 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001207
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 }
1212 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001213}
1214
1215
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001216XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001219 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 }
1221 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1222 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001223}
1224
1225
1226bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1227{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001228 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001229 const XMLUnknown* unknown = compare->ToUnknown();
1230 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001231}
1232
1233
Lee Thomason50f97b22012-02-11 16:33:40 -08001234bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1235{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001236 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001238}
1239
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001240// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001241
1242const char* XMLAttribute::Name() const
1243{
1244 return _name.GetStr();
1245}
1246
1247const char* XMLAttribute::Value() const
1248{
1249 return _value.GetStr();
1250}
1251
Lee Thomason6f381b72012-03-02 12:59:39 -08001252char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001253{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( !p || !*p ) {
1257 return 0;
1258 }
Lee Thomason22aead12012-01-23 13:29:35 -08001259
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 // Skip white space before =
1261 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001262 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 return 0;
1264 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001265
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 ++p; // move up to opening quote
1267 p = XMLUtil::SkipWhiteSpace( p );
1268 if ( *p != '\"' && *p != '\'' ) {
1269 return 0;
1270 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001271
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 char endTag[2] = { *p, 0 };
1273 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001274
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001277}
1278
1279
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001280void XMLAttribute::SetName( const char* n )
1281{
Lee Thomason624d43f2012-10-12 10:58:48 -07001282 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001283}
1284
1285
Lee Thomason2fa81722012-11-09 12:37:46 -08001286XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 if ( XMLUtil::ToInt( Value(), value )) {
1289 return XML_NO_ERROR;
1290 }
1291 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001292}
1293
1294
Lee Thomason2fa81722012-11-09 12:37:46 -08001295XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 if ( XMLUtil::ToUnsigned( Value(), value )) {
1298 return XML_NO_ERROR;
1299 }
1300 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001301}
1302
1303
Lee Thomason2fa81722012-11-09 12:37:46 -08001304XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 if ( XMLUtil::ToBool( Value(), value )) {
1307 return XML_NO_ERROR;
1308 }
1309 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001310}
1311
1312
Lee Thomason2fa81722012-11-09 12:37:46 -08001313XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 if ( XMLUtil::ToFloat( Value(), value )) {
1316 return XML_NO_ERROR;
1317 }
1318 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001319}
1320
1321
Lee Thomason2fa81722012-11-09 12:37:46 -08001322XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( XMLUtil::ToDouble( Value(), value )) {
1325 return XML_NO_ERROR;
1326 }
1327 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001328}
1329
1330
1331void XMLAttribute::SetAttribute( const char* v )
1332{
Lee Thomason624d43f2012-10-12 10:58:48 -07001333 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001334}
1335
1336
Lee Thomason1ff38e02012-02-14 18:18:16 -08001337void XMLAttribute::SetAttribute( int v )
1338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001341 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001343
1344
1345void XMLAttribute::SetAttribute( unsigned v )
1346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001350}
1351
1352
1353void XMLAttribute::SetAttribute( bool v )
1354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 char buf[BUF_SIZE];
1356 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001357 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001358}
1359
1360void XMLAttribute::SetAttribute( double v )
1361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 char buf[BUF_SIZE];
1363 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001364 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001365}
1366
1367void XMLAttribute::SetAttribute( float v )
1368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001372}
1373
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001374
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001375// --------- XMLElement ---------- //
1376XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _closingType( 0 ),
1378 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001379{
1380}
1381
1382
1383XMLElement::~XMLElement()
1384{
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 while( _rootAttribute ) {
1386 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001387 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001390}
1391
1392
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1394{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001395 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1397 return a;
1398 }
1399 }
1400 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001401}
1402
1403
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001404const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 const XMLAttribute* a = FindAttribute( name );
1407 if ( !a ) {
1408 return 0;
1409 }
1410 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1411 return a->Value();
1412 }
1413 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001414}
1415
1416
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001417const char* XMLElement::GetText() const
1418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001420 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
1422 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001423}
1424
1425
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001426void XMLElement::SetText( const char* inText )
1427{
Uli Kusterer869bb592014-01-21 01:36:16 +01001428 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001429 FirstChild()->SetValue( inText );
1430 else {
1431 XMLText* theText = GetDocument()->NewText( inText );
1432 InsertFirstChild( theText );
1433 }
1434}
1435
Lee Thomason5bb2d802014-01-24 10:42:57 -08001436
1437void XMLElement::SetText( int v )
1438{
1439 char buf[BUF_SIZE];
1440 XMLUtil::ToStr( v, buf, BUF_SIZE );
1441 SetText( buf );
1442}
1443
1444
1445void XMLElement::SetText( unsigned v )
1446{
1447 char buf[BUF_SIZE];
1448 XMLUtil::ToStr( v, buf, BUF_SIZE );
1449 SetText( buf );
1450}
1451
1452
1453void XMLElement::SetText( bool v )
1454{
1455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
1457 SetText( buf );
1458}
1459
1460
1461void XMLElement::SetText( float v )
1462{
1463 char buf[BUF_SIZE];
1464 XMLUtil::ToStr( v, buf, BUF_SIZE );
1465 SetText( buf );
1466}
1467
1468
1469void XMLElement::SetText( double v )
1470{
1471 char buf[BUF_SIZE];
1472 XMLUtil::ToStr( v, buf, BUF_SIZE );
1473 SetText( buf );
1474}
1475
1476
MortenMacFly4ee49f12013-01-14 20:03:14 +01001477XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001480 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001481 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 return XML_SUCCESS;
1483 }
1484 return XML_CAN_NOT_CONVERT_TEXT;
1485 }
1486 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001487}
1488
1489
MortenMacFly4ee49f12013-01-14 20:03:14 +01001490XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001493 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001494 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 return XML_SUCCESS;
1496 }
1497 return XML_CAN_NOT_CONVERT_TEXT;
1498 }
1499 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001500}
1501
1502
MortenMacFly4ee49f12013-01-14 20:03:14 +01001503XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001504{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001506 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001507 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 return XML_SUCCESS;
1509 }
1510 return XML_CAN_NOT_CONVERT_TEXT;
1511 }
1512 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001513}
1514
1515
MortenMacFly4ee49f12013-01-14 20:03:14 +01001516XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001519 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001520 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return XML_SUCCESS;
1522 }
1523 return XML_CAN_NOT_CONVERT_TEXT;
1524 }
1525 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001526}
1527
1528
MortenMacFly4ee49f12013-01-14 20:03:14 +01001529XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001532 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001533 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 return XML_SUCCESS;
1535 }
1536 return XML_CAN_NOT_CONVERT_TEXT;
1537 }
1538 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001539}
1540
1541
1542
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001543XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 XMLAttribute* last = 0;
1546 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1551 break;
1552 }
1553 }
1554 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001555 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1557 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 }
1561 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001562 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 }
1564 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001565 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 }
1567 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001568}
1569
1570
U-Stream\Leeae25a442012-02-17 17:48:16 -08001571void XMLElement::DeleteAttribute( const char* name )
1572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1576 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 }
1579 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001580 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001582 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 break;
1584 }
1585 prev = a;
1586 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001587}
1588
1589
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001590char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 const char* start = p;
1593 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001594
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 // Read the attributes.
1596 while( p ) {
1597 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001598 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001599 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 return 0;
1601 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001602
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001604 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001605 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1607 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001608 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001609
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001612 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 return 0;
1615 }
1616 // There is a minor bug here: if the attribute in the source xml
1617 // document is duplicated, it will not be detected and the
1618 // attribute will be doubly added. However, tracking the 'prevAttribute'
1619 // avoids re-scanning the attribute list. Preferring performance for
1620 // now, may reconsider in the future.
1621 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 }
1624 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 }
1627 prevAttribute = attrib;
1628 }
1629 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 else if ( *p == '>' ) {
1631 ++p;
1632 break;
1633 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001634 // end of the tag
1635 else if ( *p == '/' && *(p+1) == '>' ) {
1636 _closingType = CLOSED;
1637 return p+2; // done; sealed element.
1638 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 return 0;
1642 }
1643 }
1644 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001645}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001646
Dmitry-Mee3225b12014-09-03 11:03:11 +04001647void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1648{
1649 if ( attribute == 0 ) {
1650 return;
1651 }
1652 MemPool* pool = attribute->_memPool;
1653 attribute->~XMLAttribute();
1654 pool->Free( attribute );
1655}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001656
Lee Thomason67d61312012-01-24 16:01:51 -08001657//
1658// <ele></ele>
1659// <ele>foo<b>bar</b></ele>
1660//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001661char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001662{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 // Read the element name.
1664 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001665
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 // The closing element is the </element> form. It is
1667 // parsed just like a regular element then deleted from
1668 // the DOM.
1669 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 ++p;
1672 }
Lee Thomason67d61312012-01-24 16:01:51 -08001673
Lee Thomason624d43f2012-10-12 10:58:48 -07001674 p = _value.ParseName( p );
1675 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 return 0;
1677 }
Lee Thomason67d61312012-01-24 16:01:51 -08001678
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 return p;
1682 }
Lee Thomason67d61312012-01-24 16:01:51 -08001683
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 p = XMLNode::ParseDeep( p, strPair );
1685 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001686}
1687
1688
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001689
1690XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 }
1695 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1696 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1697 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1698 }
1699 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001700}
1701
1702
1703bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1704{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001705 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001707 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001708
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 const XMLAttribute* a=FirstAttribute();
1710 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001711
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 while ( a && b ) {
1713 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1714 return false;
1715 }
1716 a = a->Next();
1717 b = b->Next();
1718 }
1719 if ( a || b ) {
1720 // different count
1721 return false;
1722 }
1723 return true;
1724 }
1725 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001726}
1727
1728
Lee Thomason751da522012-02-10 08:50:51 -08001729bool XMLElement::Accept( XMLVisitor* visitor ) const
1730{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001731 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1734 if ( !node->Accept( visitor ) ) {
1735 break;
1736 }
1737 }
1738 }
1739 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001740}
Lee Thomason56bdd022012-02-09 18:16:58 -08001741
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001742
Lee Thomason3f57d272012-01-11 15:30:03 -08001743// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001744
1745// Warning: List must match 'enum XMLError'
1746const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1747 "XML_SUCCESS",
1748 "XML_NO_ATTRIBUTE",
1749 "XML_WRONG_ATTRIBUTE_TYPE",
1750 "XML_ERROR_FILE_NOT_FOUND",
1751 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1752 "XML_ERROR_FILE_READ_ERROR",
1753 "XML_ERROR_ELEMENT_MISMATCH",
1754 "XML_ERROR_PARSING_ELEMENT",
1755 "XML_ERROR_PARSING_ATTRIBUTE",
1756 "XML_ERROR_IDENTIFYING_TAG",
1757 "XML_ERROR_PARSING_TEXT",
1758 "XML_ERROR_PARSING_CDATA",
1759 "XML_ERROR_PARSING_COMMENT",
1760 "XML_ERROR_PARSING_DECLARATION",
1761 "XML_ERROR_PARSING_UNKNOWN",
1762 "XML_ERROR_EMPTY_DOCUMENT",
1763 "XML_ERROR_MISMATCHED_ELEMENT",
1764 "XML_ERROR_PARSING",
1765 "XML_CAN_NOT_CONVERT_TEXT",
1766 "XML_NO_TEXT_NODE"
1767};
1768
1769
Lee Thomason624d43f2012-10-12 10:58:48 -07001770XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 _writeBOM( false ),
1773 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001774 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 _whitespace( whitespace ),
1776 _errorStr1( 0 ),
1777 _errorStr2( 0 ),
1778 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001779{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001780 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1781 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001782}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001783
1784
Lee Thomason3f57d272012-01-11 15:30:03 -08001785XMLDocument::~XMLDocument()
1786{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001787 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001788}
1789
1790
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001791void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001792{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001793 DeleteChildren();
1794
Dmitry-Meab37df82014-11-28 12:08:36 +03001795#ifdef DEBUG
1796 const bool hadError = Error();
1797#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 _errorID = XML_NO_ERROR;
1799 _errorStr1 = 0;
1800 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001801
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 delete [] _charBuffer;
1803 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001804
1805#if 0
1806 _textPool.Trace( "text" );
1807 _elementPool.Trace( "element" );
1808 _commentPool.Trace( "comment" );
1809 _attributePool.Trace( "attribute" );
1810#endif
1811
1812#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001813 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001814 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1815 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1816 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1817 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1818 }
1819#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001820}
1821
Lee Thomason3f57d272012-01-11 15:30:03 -08001822
Lee Thomason2c85a712012-01-31 08:24:24 -08001823XMLElement* XMLDocument::NewElement( const char* name )
1824{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001825 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1827 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 ele->SetName( name );
1829 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001830}
1831
1832
Lee Thomason1ff38e02012-02-14 18:18:16 -08001833XMLComment* XMLDocument::NewComment( const char* str )
1834{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001835 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1837 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 comment->SetValue( str );
1839 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001840}
1841
1842
1843XMLText* XMLDocument::NewText( const char* str )
1844{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001845 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1847 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 text->SetValue( str );
1849 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001850}
1851
1852
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001853XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1854{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001855 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1857 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1859 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001860}
1861
1862
1863XMLUnknown* XMLDocument::NewUnknown( const char* str )
1864{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001865 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1867 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 unk->SetValue( str );
1869 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001870}
1871
Dmitry-Me01578db2014-08-19 10:18:48 +04001872static FILE* callfopen( const char* filepath, const char* mode )
1873{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001874 TIXMLASSERT( filepath );
1875 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001876#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1877 FILE* fp = 0;
1878 errno_t err = fopen_s( &fp, filepath, mode );
1879 if ( err ) {
1880 return 0;
1881 }
1882#else
1883 FILE* fp = fopen( filepath, mode );
1884#endif
1885 return fp;
1886}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001887
1888void XMLDocument::DeleteNode( XMLNode* node ) {
1889 TIXMLASSERT( node );
1890 TIXMLASSERT(node->_document == this );
1891 if (node->_parent) {
1892 node->_parent->DeleteChild( node );
1893 }
1894 else {
1895 // Isn't in the tree.
1896 // Use the parent delete.
1897 // Also, we need to mark it tracked: we 'know'
1898 // it was never used.
1899 node->_memPool->SetTracked();
1900 // Call the static XMLNode version:
1901 XMLNode::DeleteNode(node);
1902 }
1903}
1904
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001905
Lee Thomason2fa81722012-11-09 12:37:46 -08001906XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001907{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001908 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001909 FILE* fp = callfopen( filename, "rb" );
1910 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 }
1914 LoadFile( fp );
1915 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001917}
1918
Dmitry-Me901fed52015-09-25 10:29:51 +03001919// This is likely overengineered template art to have a check that unsigned long value incremented
1920// by one still fits into size_t. If size_t type is larger than unsigned long type
1921// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1922// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1923// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1924// types sizes relate to each other.
1925template
1926<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1927struct LongFitsIntoSizeTMinusOne {
1928 static bool Fits( unsigned long value )
1929 {
1930 return value < (size_t)-1;
1931 }
1932};
1933
1934template <>
1935bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1936{
1937 return true;
1938}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001939
Lee Thomason2fa81722012-11-09 12:37:46 -08001940XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001942 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001944 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001945 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001946 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1947 return _errorID;
1948 }
1949
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001951 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001953 if ( filelength == -1L ) {
1954 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1955 return _errorID;
1956 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001957
Dmitry-Me901fed52015-09-25 10:29:51 +03001958 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001959 // Cannot handle files which won't fit in buffer together with null terminator
1960 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1961 return _errorID;
1962 }
1963
Dmitry-Me72801b82015-05-07 09:41:39 +03001964 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001965 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001968
Dmitry-Me72801b82015-05-07 09:41:39 +03001969 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03001970 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 _charBuffer = new char[size+1];
1972 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 if ( read != size ) {
1974 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001977
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001979
Dmitry-Me97476b72015-01-01 16:15:57 +03001980 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001982}
1983
1984
Lee Thomason2fa81722012-11-09 12:37:46 -08001985XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001986{
Dmitry-Me01578db2014-08-19 10:18:48 +04001987 FILE* fp = callfopen( filename, "w" );
1988 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001990 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001991 }
1992 SaveFile(fp, compact);
1993 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001994 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001995}
1996
1997
Lee Thomason2fa81722012-11-09 12:37:46 -08001998XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001999{
Ant Mitchell189198f2015-03-24 16:20:36 +00002000 // Clear any error from the last save, otherwise it will get reported
2001 // for *this* call.
2002 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 XMLPrinter stream( fp, compact );
2004 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002005 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002006}
2007
Lee Thomason1ff38e02012-02-14 18:18:16 -08002008
Lee Thomason2fa81722012-11-09 12:37:46 -08002009XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002010{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002011 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002012
Lee Thomason82d32002014-02-21 22:47:18 -08002013 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002015 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 }
2017 if ( len == (size_t)(-1) ) {
2018 len = strlen( p );
2019 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002020 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 _charBuffer = new char[ len+1 ];
2022 memcpy( _charBuffer, p, len );
2023 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002024
Dmitry-Me97476b72015-01-01 16:15:57 +03002025 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002026 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002027 // clean up now essentially dangling memory.
2028 // and the parse fail can put objects in the
2029 // pools that are dead and inaccessible.
2030 DeleteChildren();
2031 _elementPool.Clear();
2032 _attributePool.Clear();
2033 _textPool.Clear();
2034 _commentPool.Clear();
2035 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002037}
2038
2039
PKEuS1c5f99e2013-07-06 11:28:39 +02002040void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002041{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002042 if ( streamer ) {
2043 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002045 else {
2046 XMLPrinter stdoutStreamer( stdout );
2047 Accept( &stdoutStreamer );
2048 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002049}
2050
2051
Lee Thomason2fa81722012-11-09 12:37:46 -08002052void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002053{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002054 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 _errorID = error;
2056 _errorStr1 = str1;
2057 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002058}
2059
Lee Thomason331596e2014-09-11 14:56:43 -07002060const char* XMLDocument::ErrorName() const
2061{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002062 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002063 const char* errorName = _errorNames[_errorID];
2064 TIXMLASSERT( errorName && errorName[0] );
2065 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002066}
Lee Thomason5cae8972012-01-24 18:03:07 -08002067
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002068void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002069{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002070 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 static const int LEN = 20;
2072 char buf1[LEN] = { 0 };
2073 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002074
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 if ( _errorStr1 ) {
2076 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 if ( _errorStr2 ) {
2079 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002081
Dmitry-Me2ad43202015-04-16 12:18:58 +03002082 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2083 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2084 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002085 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002086 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002088}
2089
Dmitry-Me97476b72015-01-01 16:15:57 +03002090void XMLDocument::Parse()
2091{
2092 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2093 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002094 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002095 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002096 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002097 if ( !*p ) {
2098 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2099 return;
2100 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002101 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002102}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002103
PKEuS1bfb9542013-08-04 13:51:17 +02002104XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002105 _elementJustOpened( false ),
2106 _firstElement( true ),
2107 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002108 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 _textDepth( -1 ),
2110 _processEntities( true ),
2111 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 _entityFlag[i] = false;
2115 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 }
2117 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002118 const char entityValue = entities[i].value;
2119 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2120 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002122 _restrictedEntityFlag[(unsigned char)'&'] = true;
2123 _restrictedEntityFlag[(unsigned char)'<'] = true;
2124 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002126}
2127
2128
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002129void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002130{
2131 va_list va;
2132 va_start( va, format );
2133
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _fp ) {
2135 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
2137 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002138 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 // Close out and re-start the va-args
2140 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002141 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002143 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002144 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002145 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002147 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002148}
2149
2150
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002151void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 for( int i=0; i<depth; ++i ) {
2154 Print( " " );
2155 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002156}
2157
2158
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002159void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 // Look for runs of bytes between entities to print.
2162 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002163
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002165 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002167 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 // Remember, char is sometimes signed. (How many times has that bitten me?)
2169 if ( *q > 0 && *q < ENTITY_RANGE ) {
2170 // Check for entities. If one is found, flush
2171 // the stream up until the entity, write the
2172 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002173 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002175 const size_t delta = q - p;
2176 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002177 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002178 Print( "%.*s", toPrint, p );
2179 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002181 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 for( int i=0; i<NUM_ENTITIES; ++i ) {
2183 if ( entities[i].value == *q ) {
2184 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002185 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 break;
2187 }
2188 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002189 if ( !entityPatternPrinted ) {
2190 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2191 TIXMLASSERT( false );
2192 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 ++p;
2194 }
2195 }
2196 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002197 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 }
2199 }
2200 // Flush the remaining string. This will be the entire
2201 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002202 TIXMLASSERT( p <= q );
2203 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "%s", p );
2205 }
Lee Thomason857b8682012-01-25 17:50:25 -08002206}
2207
U-Stream\Leeae25a442012-02-17 17:48:16 -08002208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002212 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 -07002213 Print( "%s", bom );
2214 }
2215 if ( writeDec ) {
2216 PushDeclaration( "xml version=\"1.0\"" );
2217 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002218}
2219
2220
Uli Kusterer593a33d2014-02-01 12:48:51 +01002221void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002222{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002223 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002225
Uli Kusterer593a33d2014-02-01 12:48:51 +01002226 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002228 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002229 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002232
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 _elementJustOpened = true;
2235 _firstElement = false;
2236 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002241{
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( " %s=\"", name );
2244 PrintString( value, false );
2245 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002246}
2247
2248
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002249void XMLPrinter::PushAttribute( const char* name, int v )
2250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 char buf[BUF_SIZE];
2252 XMLUtil::ToStr( v, buf, BUF_SIZE );
2253 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002254}
2255
2256
2257void XMLPrinter::PushAttribute( const char* name, unsigned v )
2258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 char buf[BUF_SIZE];
2260 XMLUtil::ToStr( v, buf, BUF_SIZE );
2261 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002262}
2263
2264
2265void XMLPrinter::PushAttribute( const char* name, bool v )
2266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 char buf[BUF_SIZE];
2268 XMLUtil::ToStr( v, buf, BUF_SIZE );
2269 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002270}
2271
2272
2273void XMLPrinter::PushAttribute( const char* name, double v )
2274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 char buf[BUF_SIZE];
2276 XMLUtil::ToStr( v, buf, BUF_SIZE );
2277 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002278}
2279
2280
Uli Kustererca412e82014-02-01 13:35:05 +01002281void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002282{
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 --_depth;
2284 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002285
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 Print( "/>" );
2288 }
2289 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002290 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 }
2294 Print( "</%s>", name );
2295 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002296
Lee Thomason624d43f2012-10-12 10:58:48 -07002297 if ( _textDepth == _depth ) {
2298 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Uli Kustererca412e82014-02-01 13:35:05 +01002300 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 Print( "\n" );
2302 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002304}
2305
2306
Dmitry-Mea092bc12014-12-23 17:57:05 +03002307void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002308{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002309 if ( !_elementJustOpened ) {
2310 return;
2311 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002312 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002314}
2315
2316
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002317void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002318{
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002320
Dmitry-Mea092bc12014-12-23 17:57:05 +03002321 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002323 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 }
2325 else {
2326 PrintString( text, true );
2327 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002328}
2329
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002330void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002332 char buf[BUF_SIZE];
2333 XMLUtil::ToStr( value, buf, BUF_SIZE );
2334 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002335}
2336
2337
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002338void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 char buf[BUF_SIZE];
2341 XMLUtil::ToStr( value, buf, BUF_SIZE );
2342 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002343}
2344
2345
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002346void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 char buf[BUF_SIZE];
2349 XMLUtil::ToStr( value, buf, BUF_SIZE );
2350 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002351}
2352
2353
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002354void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 char buf[BUF_SIZE];
2357 XMLUtil::ToStr( value, buf, BUF_SIZE );
2358 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002359}
2360
2361
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002362void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 char buf[BUF_SIZE];
2365 XMLUtil::ToStr( value, buf, BUF_SIZE );
2366 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002367}
2368
Lee Thomason5cae8972012-01-24 18:03:07 -08002369
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002370void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002371{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002372 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002374 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002377 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002379}
Lee Thomason751da522012-02-10 08:50:51 -08002380
2381
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002382void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002383{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002384 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002387 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002389 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002390 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002391}
2392
2393
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002394void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002395{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002396 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002399 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002402 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002403}
2404
2405
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002406bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002407{
Lee Thomason624d43f2012-10-12 10:58:48 -07002408 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002409 if ( doc.HasBOM() ) {
2410 PushHeader( true, false );
2411 }
2412 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002413}
2414
2415
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002416bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002417{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002418 const XMLElement* parentElem = 0;
2419 if ( element.Parent() ) {
2420 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002421 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002422 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002423 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 while ( attribute ) {
2425 PushAttribute( attribute->Name(), attribute->Value() );
2426 attribute = attribute->Next();
2427 }
2428 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002429}
2430
2431
Uli Kustererca412e82014-02-01 13:35:05 +01002432bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002433{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002434 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002435 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002436}
2437
2438
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002439bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 PushText( text.Value(), text.CData() );
2442 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002443}
2444
2445
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002446bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 PushComment( comment.Value() );
2449 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002450}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002451
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002452bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 PushDeclaration( declaration.Value() );
2455 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002456}
2457
2458
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002459bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 PushUnknown( unknown.Value() );
2462 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002463}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002464
Lee Thomason685b8952012-11-12 13:00:06 -08002465} // namespace tinyxml2
2466