blob: 510fc82d1a9013351e81608448e506d415840b3d [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 );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400779 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800780}
781
782
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800783XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
784{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300785 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300786 if ( addThis->_document != _document ) {
787 TIXMLASSERT( false );
788 return 0;
789 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800790 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791
Lee Thomason624d43f2012-10-12 10:58:48 -0700792 if ( _lastChild ) {
793 TIXMLASSERT( _firstChild );
794 TIXMLASSERT( _lastChild->_next == 0 );
795 _lastChild->_next = addThis;
796 addThis->_prev = _lastChild;
797 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800798
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
801 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700802 TIXMLASSERT( _firstChild == 0 );
803 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800804
Lee Thomason624d43f2012-10-12 10:58:48 -0700805 addThis->_prev = 0;
806 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700808 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800810}
811
812
Lee Thomason1ff38e02012-02-14 18:18:16 -0800813XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
814{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300815 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300816 if ( addThis->_document != _document ) {
817 TIXMLASSERT( false );
818 return 0;
819 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800820 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700821
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 if ( _firstChild ) {
823 TIXMLASSERT( _lastChild );
824 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800825
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 _firstChild->_prev = addThis;
827 addThis->_next = _firstChild;
828 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800829
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
832 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700833 TIXMLASSERT( _lastChild == 0 );
834 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835
Lee Thomason624d43f2012-10-12 10:58:48 -0700836 addThis->_prev = 0;
837 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400840 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800841}
842
843
844XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
845{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300846 TIXMLASSERT( addThis );
847 if ( addThis->_document != _document ) {
848 TIXMLASSERT( false );
849 return 0;
850 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700851
Dmitry-Meabb2d042014-12-09 12:59:31 +0300852 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700853
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300855 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 return 0;
857 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800858
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 // The last node or the only node.
861 return InsertEndChild( addThis );
862 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800863 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700864 addThis->_prev = afterThis;
865 addThis->_next = afterThis->_next;
866 afterThis->_next->_prev = addThis;
867 afterThis->_next = addThis;
868 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870}
871
872
873
874
Dmitry-Me886ad972015-07-22 11:00:51 +0300875const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800876{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300877 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
878 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300880 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 return element;
882 }
883 }
884 }
885 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800886}
887
888
Dmitry-Me886ad972015-07-22 11:00:51 +0300889const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800890{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300891 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
892 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300894 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 return element;
896 }
897 }
898 }
899 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800900}
901
902
Dmitry-Me886ad972015-07-22 11:00:51 +0300903const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800904{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300905 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400906 const XMLElement* element = node->ToElement();
907 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300908 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400909 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700910 }
911 }
912 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800913}
914
915
Dmitry-Me886ad972015-07-22 11:00:51 +0300916const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800917{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300918 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400919 const XMLElement* element = node->ToElement();
920 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300921 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400922 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 }
924 }
925 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800926}
927
928
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800929char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800930{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 // This is a recursive method, but thinking about it "at the current level"
932 // it is a pretty simple flat list:
933 // <foo/>
934 // <!-- comment -->
935 //
936 // With a special case:
937 // <foo>
938 // </foo>
939 // <!-- comment -->
940 //
941 // Where the closing element (/foo) *must* be the next thing after the opening
942 // element, and the names must match. BUT the tricky bit is that the closing
943 // element will be read by the child.
944 //
945 // 'endTag' is the end tag for this node, it is returned by a call to a child.
946 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800947
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 while( p && *p ) {
949 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800950
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300952 if ( node == 0 ) {
953 break;
954 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800955
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 StrPair endTag;
957 p = node->ParseDeep( p, &endTag );
958 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400959 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700960 if ( !_document->Error() ) {
961 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 }
963 break;
964 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800965
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530966 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530967 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530968 // A declaration can only be the first child of a document.
969 // Set error, if document already has children.
970 if ( !_document->NoChildren() ) {
971 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
972 DeleteNode( decl );
973 break;
974 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530975 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530976
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400977 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500979 // We read the end tag. Return it to the parent.
980 if ( ele->ClosingType() == XMLElement::CLOSING ) {
981 if ( parentEnd ) {
982 ele->_value.TransferTo( parentEnd );
983 }
984 node->_memPool->SetTracked(); // created and then immediately deleted.
985 DeleteNode( node );
986 return p;
987 }
988
989 // Handle an end tag returned to this level.
990 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400991 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300992 if ( endTag.Empty() ) {
993 if ( ele->ClosingType() == XMLElement::OPEN ) {
994 mismatch = true;
995 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300997 else {
998 if ( ele->ClosingType() != XMLElement::OPEN ) {
999 mismatch = true;
1000 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001001 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001002 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 }
1004 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001005 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001006 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001007 DeleteNode( node );
1008 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001009 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 }
JayXondbfdd8f2014-12-12 20:07:14 -05001011 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 }
1013 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001014}
1015
Dmitry-Mee3225b12014-09-03 11:03:11 +04001016void XMLNode::DeleteNode( XMLNode* node )
1017{
1018 if ( node == 0 ) {
1019 return;
1020 }
1021 MemPool* pool = node->_memPool;
1022 node->~XMLNode();
1023 pool->Free( node );
1024}
1025
Lee Thomason3cebdc42015-01-05 17:16:28 -08001026void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001027{
1028 TIXMLASSERT( insertThis );
1029 TIXMLASSERT( insertThis->_document == _document );
1030
1031 if ( insertThis->_parent )
1032 insertThis->_parent->Unlink( insertThis );
1033 else
1034 insertThis->_memPool->SetTracked();
1035}
1036
Lee Thomason5492a1c2012-01-23 15:32:10 -08001037// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001038char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 const char* start = p;
1041 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 return p;
1047 }
1048 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1050 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001051 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001053
Lee Thomason624d43f2012-10-12 10:58:48 -07001054 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 if ( p && *p ) {
1056 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001057 }
1058 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001059 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 }
1061 }
1062 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001063}
1064
1065
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001066XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1067{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001069 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
1071 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1072 text->SetCData( this->CData() );
1073 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001074}
1075
1076
1077bool XMLText::ShallowEqual( const XMLNode* compare ) const
1078{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001079 const XMLText* text = compare->ToText();
1080 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001081}
1082
1083
Lee Thomason56bdd022012-02-09 18:16:58 -08001084bool XMLText::Accept( XMLVisitor* visitor ) const
1085{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001086 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001088}
1089
1090
Lee Thomason3f57d272012-01-11 15:30:03 -08001091// --------- XMLComment ---------- //
1092
Lee Thomasone4422302012-01-20 17:59:50 -08001093XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001094{
1095}
1096
1097
Lee Thomasonce0763e2012-01-11 15:43:54 -08001098XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001099{
Lee Thomason3f57d272012-01-11 15:30:03 -08001100}
1101
1102
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001103char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001104{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 // Comment parses as text.
1106 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001109 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 }
1111 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001112}
1113
1114
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001115XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001118 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 }
1120 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1121 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001122}
1123
1124
1125bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1126{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001127 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001128 const XMLComment* comment = compare->ToComment();
1129 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001130}
1131
1132
Lee Thomason751da522012-02-10 08:50:51 -08001133bool XMLComment::Accept( XMLVisitor* visitor ) const
1134{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001135 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001137}
Lee Thomason56bdd022012-02-09 18:16:58 -08001138
1139
Lee Thomason50f97b22012-02-11 16:33:40 -08001140// --------- XMLDeclaration ---------- //
1141
1142XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1143{
1144}
1145
1146
1147XMLDeclaration::~XMLDeclaration()
1148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001150}
1151
1152
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001153char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001154{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 // Declaration parses as text.
1156 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 }
1161 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001162}
1163
1164
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001165XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001168 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 }
1170 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1171 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172}
1173
1174
1175bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1176{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001177 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001178 const XMLDeclaration* declaration = compare->ToDeclaration();
1179 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001180}
1181
1182
1183
Lee Thomason50f97b22012-02-11 16:33:40 -08001184bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1185{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001186 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001188}
1189
1190// --------- XMLUnknown ---------- //
1191
1192XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1193{
1194}
1195
1196
1197XMLUnknown::~XMLUnknown()
1198{
1199}
1200
1201
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001202char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 // Unknown parses as text.
1205 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001206
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 }
1211 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001212}
1213
1214
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001215XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001218 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 }
1220 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1221 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001222}
1223
1224
1225bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1226{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001227 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001228 const XMLUnknown* unknown = compare->ToUnknown();
1229 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001230}
1231
1232
Lee Thomason50f97b22012-02-11 16:33:40 -08001233bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1234{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001235 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001237}
1238
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001239// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001240
1241const char* XMLAttribute::Name() const
1242{
1243 return _name.GetStr();
1244}
1245
1246const char* XMLAttribute::Value() const
1247{
1248 return _value.GetStr();
1249}
1250
Lee Thomason6f381b72012-03-02 12:59:39 -08001251char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( !p || !*p ) {
1256 return 0;
1257 }
Lee Thomason22aead12012-01-23 13:29:35 -08001258
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 // Skip white space before =
1260 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001261 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 return 0;
1263 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001264
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 ++p; // move up to opening quote
1266 p = XMLUtil::SkipWhiteSpace( p );
1267 if ( *p != '\"' && *p != '\'' ) {
1268 return 0;
1269 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001270
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 char endTag[2] = { *p, 0 };
1272 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001273
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001276}
1277
1278
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001279void XMLAttribute::SetName( const char* n )
1280{
Lee Thomason624d43f2012-10-12 10:58:48 -07001281 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001282}
1283
1284
Lee Thomason2fa81722012-11-09 12:37:46 -08001285XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 if ( XMLUtil::ToInt( Value(), value )) {
1288 return XML_NO_ERROR;
1289 }
1290 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001291}
1292
1293
Lee Thomason2fa81722012-11-09 12:37:46 -08001294XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( XMLUtil::ToUnsigned( Value(), value )) {
1297 return XML_NO_ERROR;
1298 }
1299 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001300}
1301
1302
Lee Thomason2fa81722012-11-09 12:37:46 -08001303XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( XMLUtil::ToBool( Value(), value )) {
1306 return XML_NO_ERROR;
1307 }
1308 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001309}
1310
1311
Lee Thomason2fa81722012-11-09 12:37:46 -08001312XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 if ( XMLUtil::ToFloat( Value(), value )) {
1315 return XML_NO_ERROR;
1316 }
1317 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001318}
1319
1320
Lee Thomason2fa81722012-11-09 12:37:46 -08001321XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001322{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( XMLUtil::ToDouble( Value(), value )) {
1324 return XML_NO_ERROR;
1325 }
1326 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001327}
1328
1329
1330void XMLAttribute::SetAttribute( const char* v )
1331{
Lee Thomason624d43f2012-10-12 10:58:48 -07001332 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001333}
1334
1335
Lee Thomason1ff38e02012-02-14 18:18:16 -08001336void XMLAttribute::SetAttribute( int v )
1337{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 char buf[BUF_SIZE];
1339 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001340 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001341}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001342
1343
1344void XMLAttribute::SetAttribute( unsigned v )
1345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 char buf[BUF_SIZE];
1347 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001348 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001349}
1350
1351
1352void XMLAttribute::SetAttribute( bool v )
1353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 char buf[BUF_SIZE];
1355 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001357}
1358
1359void XMLAttribute::SetAttribute( double v )
1360{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 char buf[BUF_SIZE];
1362 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001364}
1365
1366void XMLAttribute::SetAttribute( float v )
1367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 char buf[BUF_SIZE];
1369 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001370 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001371}
1372
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001373
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001374// --------- XMLElement ---------- //
1375XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 _closingType( 0 ),
1377 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001378{
1379}
1380
1381
1382XMLElement::~XMLElement()
1383{
Lee Thomason624d43f2012-10-12 10:58:48 -07001384 while( _rootAttribute ) {
1385 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001386 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001387 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001389}
1390
1391
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001392const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1393{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001394 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1396 return a;
1397 }
1398 }
1399 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001400}
1401
1402
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001403const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 const XMLAttribute* a = FindAttribute( name );
1406 if ( !a ) {
1407 return 0;
1408 }
1409 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1410 return a->Value();
1411 }
1412 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001413}
1414
1415
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001416const char* XMLElement::GetText() const
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001419 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001422}
1423
1424
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001425void XMLElement::SetText( const char* inText )
1426{
Uli Kusterer869bb592014-01-21 01:36:16 +01001427 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001428 FirstChild()->SetValue( inText );
1429 else {
1430 XMLText* theText = GetDocument()->NewText( inText );
1431 InsertFirstChild( theText );
1432 }
1433}
1434
Lee Thomason5bb2d802014-01-24 10:42:57 -08001435
1436void XMLElement::SetText( int v )
1437{
1438 char buf[BUF_SIZE];
1439 XMLUtil::ToStr( v, buf, BUF_SIZE );
1440 SetText( buf );
1441}
1442
1443
1444void XMLElement::SetText( unsigned v )
1445{
1446 char buf[BUF_SIZE];
1447 XMLUtil::ToStr( v, buf, BUF_SIZE );
1448 SetText( buf );
1449}
1450
1451
1452void XMLElement::SetText( bool v )
1453{
1454 char buf[BUF_SIZE];
1455 XMLUtil::ToStr( v, buf, BUF_SIZE );
1456 SetText( buf );
1457}
1458
1459
1460void XMLElement::SetText( float v )
1461{
1462 char buf[BUF_SIZE];
1463 XMLUtil::ToStr( v, buf, BUF_SIZE );
1464 SetText( buf );
1465}
1466
1467
1468void XMLElement::SetText( double v )
1469{
1470 char buf[BUF_SIZE];
1471 XMLUtil::ToStr( v, buf, BUF_SIZE );
1472 SetText( buf );
1473}
1474
1475
MortenMacFly4ee49f12013-01-14 20:03:14 +01001476XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001479 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001480 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 return XML_SUCCESS;
1482 }
1483 return XML_CAN_NOT_CONVERT_TEXT;
1484 }
1485 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001486}
1487
1488
MortenMacFly4ee49f12013-01-14 20:03:14 +01001489XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001492 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001493 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 return XML_SUCCESS;
1495 }
1496 return XML_CAN_NOT_CONVERT_TEXT;
1497 }
1498 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001499}
1500
1501
MortenMacFly4ee49f12013-01-14 20:03:14 +01001502XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001503{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001505 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001506 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 return XML_SUCCESS;
1508 }
1509 return XML_CAN_NOT_CONVERT_TEXT;
1510 }
1511 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001512}
1513
1514
MortenMacFly4ee49f12013-01-14 20:03:14 +01001515XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001516{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001518 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001519 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 return XML_SUCCESS;
1521 }
1522 return XML_CAN_NOT_CONVERT_TEXT;
1523 }
1524 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001525}
1526
1527
MortenMacFly4ee49f12013-01-14 20:03:14 +01001528XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001531 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001532 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 return XML_SUCCESS;
1534 }
1535 return XML_CAN_NOT_CONVERT_TEXT;
1536 }
1537 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001538}
1539
1540
1541
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001542XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1543{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 XMLAttribute* last = 0;
1545 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1550 break;
1551 }
1552 }
1553 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001554 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001555 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1556 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 }
1560 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001561 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 }
1563 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001564 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 }
1566 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001567}
1568
1569
U-Stream\Leeae25a442012-02-17 17:48:16 -08001570void XMLElement::DeleteAttribute( const char* name )
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001573 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1575 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001576 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 }
1578 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001579 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001581 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 break;
1583 }
1584 prev = a;
1585 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001586}
1587
1588
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001589char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 const char* start = p;
1592 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001593
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 // Read the attributes.
1595 while( p ) {
1596 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001597 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 return 0;
1600 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001601
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001603 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001604 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1606 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001607 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001608
Lee Thomason624d43f2012-10-12 10:58:48 -07001609 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001611 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 return 0;
1614 }
1615 // There is a minor bug here: if the attribute in the source xml
1616 // document is duplicated, it will not be detected and the
1617 // attribute will be doubly added. However, tracking the 'prevAttribute'
1618 // avoids re-scanning the attribute list. Preferring performance for
1619 // now, may reconsider in the future.
1620 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 }
1623 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 }
1626 prevAttribute = attrib;
1627 }
1628 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 else if ( *p == '>' ) {
1630 ++p;
1631 break;
1632 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001633 // end of the tag
1634 else if ( *p == '/' && *(p+1) == '>' ) {
1635 _closingType = CLOSED;
1636 return p+2; // done; sealed element.
1637 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001639 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 return 0;
1641 }
1642 }
1643 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001644}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001645
Dmitry-Mee3225b12014-09-03 11:03:11 +04001646void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1647{
1648 if ( attribute == 0 ) {
1649 return;
1650 }
1651 MemPool* pool = attribute->_memPool;
1652 attribute->~XMLAttribute();
1653 pool->Free( attribute );
1654}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001655
Lee Thomason67d61312012-01-24 16:01:51 -08001656//
1657// <ele></ele>
1658// <ele>foo<b>bar</b></ele>
1659//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001660char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001661{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 // Read the element name.
1663 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001664
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 // The closing element is the </element> form. It is
1666 // parsed just like a regular element then deleted from
1667 // the DOM.
1668 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 ++p;
1671 }
Lee Thomason67d61312012-01-24 16:01:51 -08001672
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 p = _value.ParseName( p );
1674 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001675 return 0;
1676 }
Lee Thomason67d61312012-01-24 16:01:51 -08001677
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 return p;
1681 }
Lee Thomason67d61312012-01-24 16:01:51 -08001682
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 p = XMLNode::ParseDeep( p, strPair );
1684 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001685}
1686
1687
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001688
1689XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1690{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 }
1694 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1695 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1696 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1697 }
1698 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001699}
1700
1701
1702bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1703{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001704 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001706 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001707
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 const XMLAttribute* a=FirstAttribute();
1709 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001710
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 while ( a && b ) {
1712 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1713 return false;
1714 }
1715 a = a->Next();
1716 b = b->Next();
1717 }
1718 if ( a || b ) {
1719 // different count
1720 return false;
1721 }
1722 return true;
1723 }
1724 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001725}
1726
1727
Lee Thomason751da522012-02-10 08:50:51 -08001728bool XMLElement::Accept( XMLVisitor* visitor ) const
1729{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001730 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1733 if ( !node->Accept( visitor ) ) {
1734 break;
1735 }
1736 }
1737 }
1738 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001739}
Lee Thomason56bdd022012-02-09 18:16:58 -08001740
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001741
Lee Thomason3f57d272012-01-11 15:30:03 -08001742// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001743
1744// Warning: List must match 'enum XMLError'
1745const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1746 "XML_SUCCESS",
1747 "XML_NO_ATTRIBUTE",
1748 "XML_WRONG_ATTRIBUTE_TYPE",
1749 "XML_ERROR_FILE_NOT_FOUND",
1750 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1751 "XML_ERROR_FILE_READ_ERROR",
1752 "XML_ERROR_ELEMENT_MISMATCH",
1753 "XML_ERROR_PARSING_ELEMENT",
1754 "XML_ERROR_PARSING_ATTRIBUTE",
1755 "XML_ERROR_IDENTIFYING_TAG",
1756 "XML_ERROR_PARSING_TEXT",
1757 "XML_ERROR_PARSING_CDATA",
1758 "XML_ERROR_PARSING_COMMENT",
1759 "XML_ERROR_PARSING_DECLARATION",
1760 "XML_ERROR_PARSING_UNKNOWN",
1761 "XML_ERROR_EMPTY_DOCUMENT",
1762 "XML_ERROR_MISMATCHED_ELEMENT",
1763 "XML_ERROR_PARSING",
1764 "XML_CAN_NOT_CONVERT_TEXT",
1765 "XML_NO_TEXT_NODE"
1766};
1767
1768
Lee Thomason624d43f2012-10-12 10:58:48 -07001769XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 _writeBOM( false ),
1772 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001773 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 _whitespace( whitespace ),
1775 _errorStr1( 0 ),
1776 _errorStr2( 0 ),
1777 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001778{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001779 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1780 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001781}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001782
1783
Lee Thomason3f57d272012-01-11 15:30:03 -08001784XMLDocument::~XMLDocument()
1785{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001786 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001787}
1788
1789
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001790void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001791{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001792 DeleteChildren();
1793
Dmitry-Meab37df82014-11-28 12:08:36 +03001794#ifdef DEBUG
1795 const bool hadError = Error();
1796#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 _errorID = XML_NO_ERROR;
1798 _errorStr1 = 0;
1799 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001800
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 delete [] _charBuffer;
1802 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001803
1804#if 0
1805 _textPool.Trace( "text" );
1806 _elementPool.Trace( "element" );
1807 _commentPool.Trace( "comment" );
1808 _attributePool.Trace( "attribute" );
1809#endif
1810
1811#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001812 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001813 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1814 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1815 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1816 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1817 }
1818#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001819}
1820
Lee Thomason3f57d272012-01-11 15:30:03 -08001821
Lee Thomason2c85a712012-01-31 08:24:24 -08001822XMLElement* XMLDocument::NewElement( const char* name )
1823{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001824 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1826 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 ele->SetName( name );
1828 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001829}
1830
1831
Lee Thomason1ff38e02012-02-14 18:18:16 -08001832XMLComment* XMLDocument::NewComment( const char* str )
1833{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001834 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1836 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 comment->SetValue( str );
1838 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001839}
1840
1841
1842XMLText* XMLDocument::NewText( const char* str )
1843{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001844 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1846 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 text->SetValue( str );
1848 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001849}
1850
1851
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001852XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1853{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001854 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1856 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1858 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001859}
1860
1861
1862XMLUnknown* XMLDocument::NewUnknown( const char* str )
1863{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001864 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1866 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 unk->SetValue( str );
1868 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001869}
1870
Dmitry-Me01578db2014-08-19 10:18:48 +04001871static FILE* callfopen( const char* filepath, const char* mode )
1872{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001873 TIXMLASSERT( filepath );
1874 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001875#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1876 FILE* fp = 0;
1877 errno_t err = fopen_s( &fp, filepath, mode );
1878 if ( err ) {
1879 return 0;
1880 }
1881#else
1882 FILE* fp = fopen( filepath, mode );
1883#endif
1884 return fp;
1885}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001886
1887void XMLDocument::DeleteNode( XMLNode* node ) {
1888 TIXMLASSERT( node );
1889 TIXMLASSERT(node->_document == this );
1890 if (node->_parent) {
1891 node->_parent->DeleteChild( node );
1892 }
1893 else {
1894 // Isn't in the tree.
1895 // Use the parent delete.
1896 // Also, we need to mark it tracked: we 'know'
1897 // it was never used.
1898 node->_memPool->SetTracked();
1899 // Call the static XMLNode version:
1900 XMLNode::DeleteNode(node);
1901 }
1902}
1903
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001904
Lee Thomason2fa81722012-11-09 12:37:46 -08001905XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001906{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001907 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001908 FILE* fp = callfopen( filename, "rb" );
1909 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 }
1913 LoadFile( fp );
1914 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001916}
1917
Dmitry-Me901fed52015-09-25 10:29:51 +03001918// This is likely overengineered template art to have a check that unsigned long value incremented
1919// by one still fits into size_t. If size_t type is larger than unsigned long type
1920// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1921// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1922// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1923// types sizes relate to each other.
1924template
1925<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1926struct LongFitsIntoSizeTMinusOne {
1927 static bool Fits( unsigned long value )
1928 {
1929 return value < (size_t)-1;
1930 }
1931};
1932
1933template <>
1934bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1935{
1936 return true;
1937}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001938
Lee Thomason2fa81722012-11-09 12:37:46 -08001939XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001940{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001941 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001942
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001943 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001944 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001945 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1946 return _errorID;
1947 }
1948
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001950 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001952 if ( filelength == -1L ) {
1953 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1954 return _errorID;
1955 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001956
Dmitry-Me901fed52015-09-25 10:29:51 +03001957 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001958 // Cannot handle files which won't fit in buffer together with null terminator
1959 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1960 return _errorID;
1961 }
1962
Dmitry-Me72801b82015-05-07 09:41:39 +03001963 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001964 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001965 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001967
Dmitry-Me72801b82015-05-07 09:41:39 +03001968 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03001969 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _charBuffer = new char[size+1];
1971 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 if ( read != size ) {
1973 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001976
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001978
Dmitry-Me97476b72015-01-01 16:15:57 +03001979 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001980 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001981}
1982
1983
Lee Thomason2fa81722012-11-09 12:37:46 -08001984XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001985{
Dmitry-Me01578db2014-08-19 10:18:48 +04001986 FILE* fp = callfopen( filename, "w" );
1987 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
1991 SaveFile(fp, compact);
1992 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001994}
1995
1996
Lee Thomason2fa81722012-11-09 12:37:46 -08001997XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001998{
Ant Mitchell189198f2015-03-24 16:20:36 +00001999 // Clear any error from the last save, otherwise it will get reported
2000 // for *this* call.
2001 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 XMLPrinter stream( fp, compact );
2003 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002005}
2006
Lee Thomason1ff38e02012-02-14 18:18:16 -08002007
Lee Thomason2fa81722012-11-09 12:37:46 -08002008XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002009{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002010 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002011
Lee Thomason82d32002014-02-21 22:47:18 -08002012 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002014 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 }
2016 if ( len == (size_t)(-1) ) {
2017 len = strlen( p );
2018 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002019 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 _charBuffer = new char[ len+1 ];
2021 memcpy( _charBuffer, p, len );
2022 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002023
Dmitry-Me97476b72015-01-01 16:15:57 +03002024 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002025 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002026 // clean up now essentially dangling memory.
2027 // and the parse fail can put objects in the
2028 // pools that are dead and inaccessible.
2029 DeleteChildren();
2030 _elementPool.Clear();
2031 _attributePool.Clear();
2032 _textPool.Clear();
2033 _commentPool.Clear();
2034 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002036}
2037
2038
PKEuS1c5f99e2013-07-06 11:28:39 +02002039void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002040{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002041 if ( streamer ) {
2042 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002044 else {
2045 XMLPrinter stdoutStreamer( stdout );
2046 Accept( &stdoutStreamer );
2047 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002048}
2049
2050
Lee Thomason2fa81722012-11-09 12:37:46 -08002051void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002052{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002053 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 _errorID = error;
2055 _errorStr1 = str1;
2056 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002057}
2058
Lee Thomason331596e2014-09-11 14:56:43 -07002059const char* XMLDocument::ErrorName() const
2060{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002061 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002062 const char* errorName = _errorNames[_errorID];
2063 TIXMLASSERT( errorName && errorName[0] );
2064 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002065}
Lee Thomason5cae8972012-01-24 18:03:07 -08002066
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002067void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002068{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002069 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 static const int LEN = 20;
2071 char buf1[LEN] = { 0 };
2072 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002073
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 if ( _errorStr1 ) {
2075 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 if ( _errorStr2 ) {
2078 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002080
Dmitry-Me2ad43202015-04-16 12:18:58 +03002081 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2082 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2083 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002084 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002085 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002087}
2088
Dmitry-Me97476b72015-01-01 16:15:57 +03002089void XMLDocument::Parse()
2090{
2091 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2092 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002093 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002094 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002095 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002096 if ( !*p ) {
2097 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2098 return;
2099 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002100 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002101}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002102
PKEuS1bfb9542013-08-04 13:51:17 +02002103XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002104 _elementJustOpened( false ),
2105 _firstElement( true ),
2106 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002107 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002108 _textDepth( -1 ),
2109 _processEntities( true ),
2110 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 _entityFlag[i] = false;
2114 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
2116 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002117 const char entityValue = entities[i].value;
2118 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2119 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002121 _restrictedEntityFlag[(unsigned char)'&'] = true;
2122 _restrictedEntityFlag[(unsigned char)'<'] = true;
2123 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002125}
2126
2127
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002128void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002129{
2130 va_list va;
2131 va_start( va, format );
2132
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 if ( _fp ) {
2134 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 }
2136 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002137 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 // Close out and re-start the va-args
2139 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002140 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002142 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002143 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002144 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002146 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002147}
2148
2149
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002150void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 for( int i=0; i<depth; ++i ) {
2153 Print( " " );
2154 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002155}
2156
2157
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002158void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 // Look for runs of bytes between entities to print.
2161 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002162
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002164 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002166 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 // Remember, char is sometimes signed. (How many times has that bitten me?)
2168 if ( *q > 0 && *q < ENTITY_RANGE ) {
2169 // Check for entities. If one is found, flush
2170 // the stream up until the entity, write the
2171 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002172 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002174 const size_t delta = q - p;
2175 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002176 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002177 Print( "%.*s", toPrint, p );
2178 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002180 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 for( int i=0; i<NUM_ENTITIES; ++i ) {
2182 if ( entities[i].value == *q ) {
2183 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002184 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 break;
2186 }
2187 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002188 if ( !entityPatternPrinted ) {
2189 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2190 TIXMLASSERT( false );
2191 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 ++p;
2193 }
2194 }
2195 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002196 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 }
2198 }
2199 // Flush the remaining string. This will be the entire
2200 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002201 TIXMLASSERT( p <= q );
2202 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 Print( "%s", p );
2204 }
Lee Thomason857b8682012-01-25 17:50:25 -08002205}
2206
U-Stream\Leeae25a442012-02-17 17:48:16 -08002207
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002208void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002211 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 -07002212 Print( "%s", bom );
2213 }
2214 if ( writeDec ) {
2215 PushDeclaration( "xml version=\"1.0\"" );
2216 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002217}
2218
2219
Uli Kusterer593a33d2014-02-01 12:48:51 +01002220void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002221{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002222 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002224
Uli Kusterer593a33d2014-02-01 12:48:51 +01002225 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002227 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002228 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002231
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _elementJustOpened = true;
2234 _firstElement = false;
2235 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002236}
2237
2238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002240{
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 Print( " %s=\"", name );
2243 PrintString( value, false );
2244 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002245}
2246
2247
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002248void XMLPrinter::PushAttribute( const char* name, int v )
2249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 char buf[BUF_SIZE];
2251 XMLUtil::ToStr( v, buf, BUF_SIZE );
2252 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002253}
2254
2255
2256void XMLPrinter::PushAttribute( const char* name, unsigned v )
2257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 char buf[BUF_SIZE];
2259 XMLUtil::ToStr( v, buf, BUF_SIZE );
2260 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002261}
2262
2263
2264void XMLPrinter::PushAttribute( const char* name, bool v )
2265{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 char buf[BUF_SIZE];
2267 XMLUtil::ToStr( v, buf, BUF_SIZE );
2268 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002269}
2270
2271
2272void XMLPrinter::PushAttribute( const char* name, double v )
2273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 char buf[BUF_SIZE];
2275 XMLUtil::ToStr( v, buf, BUF_SIZE );
2276 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002277}
2278
2279
Uli Kustererca412e82014-02-01 13:35:05 +01002280void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002281{
Lee Thomason624d43f2012-10-12 10:58:48 -07002282 --_depth;
2283 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002284
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 Print( "/>" );
2287 }
2288 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002289 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
2293 Print( "</%s>", name );
2294 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002295
Lee Thomason624d43f2012-10-12 10:58:48 -07002296 if ( _textDepth == _depth ) {
2297 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 }
Uli Kustererca412e82014-02-01 13:35:05 +01002299 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 Print( "\n" );
2301 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002303}
2304
2305
Dmitry-Mea092bc12014-12-23 17:57:05 +03002306void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002307{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002308 if ( !_elementJustOpened ) {
2309 return;
2310 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002313}
2314
2315
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002316void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002317{
Lee Thomason624d43f2012-10-12 10:58:48 -07002318 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002319
Dmitry-Mea092bc12014-12-23 17:57:05 +03002320 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002321 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002322 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 }
2324 else {
2325 PrintString( text, true );
2326 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002327}
2328
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002329void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 char buf[BUF_SIZE];
2332 XMLUtil::ToStr( value, buf, BUF_SIZE );
2333 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002334}
2335
2336
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002337void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 char buf[BUF_SIZE];
2340 XMLUtil::ToStr( value, buf, BUF_SIZE );
2341 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002342}
2343
2344
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002345void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 char buf[BUF_SIZE];
2348 XMLUtil::ToStr( value, buf, BUF_SIZE );
2349 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002350}
2351
2352
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002353void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 char buf[BUF_SIZE];
2356 XMLUtil::ToStr( value, buf, BUF_SIZE );
2357 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002358}
2359
2360
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002361void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 char buf[BUF_SIZE];
2364 XMLUtil::ToStr( value, buf, BUF_SIZE );
2365 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002366}
2367
Lee Thomason5cae8972012-01-24 18:03:07 -08002368
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002369void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002370{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002371 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002378}
Lee Thomason751da522012-02-10 08:50:51 -08002379
2380
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002381void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002382{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002383 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002390}
2391
2392
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002393void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002394{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002395 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002396 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002398 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002399 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002400 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002401 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002402}
2403
2404
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002405bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002406{
Lee Thomason624d43f2012-10-12 10:58:48 -07002407 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 if ( doc.HasBOM() ) {
2409 PushHeader( true, false );
2410 }
2411 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002412}
2413
2414
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002415bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002416{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002417 const XMLElement* parentElem = 0;
2418 if ( element.Parent() ) {
2419 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002420 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002421 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002422 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 while ( attribute ) {
2424 PushAttribute( attribute->Name(), attribute->Value() );
2425 attribute = attribute->Next();
2426 }
2427 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002428}
2429
2430
Uli Kustererca412e82014-02-01 13:35:05 +01002431bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002432{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002433 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002434 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002435}
2436
2437
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002438bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 PushText( text.Value(), text.CData() );
2441 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002442}
2443
2444
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002445bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 PushComment( comment.Value() );
2448 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002449}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002450
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002451bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 PushDeclaration( declaration.Value() );
2454 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002455}
2456
2457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002458bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002460 PushUnknown( unknown.Value() );
2461 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002462}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002463
Lee Thomason685b8952012-11-12 13:00:06 -08002464} // namespace tinyxml2
2465