blob: 4099fc88d56f2f56e1cf344ec5193d4252ff737e [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Lee Thomason29658802014-11-27 22:31:11 -0800152 TIXMLASSERT( other->_flags == 0 );
153 TIXMLASSERT( other->_start == 0 );
154 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300155
Lee Thomason29658802014-11-27 22:31:11 -0800156 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300157
Lee Thomason29658802014-11-27 22:31:11 -0800158 other->_flags = _flags;
159 other->_start = _start;
160 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300161
162 _flags = 0;
163 _start = 0;
164 _end = 0;
165}
166
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800167void StrPair::Reset()
168{
Lee Thomason120b3a62012-10-12 10:06:59 -0700169 if ( _flags & NEEDS_DELETE ) {
170 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700171 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700172 _flags = 0;
173 _start = 0;
174 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800175}
176
177
178void StrPair::SetStr( const char* str, int flags )
179{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300180 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700181 Reset();
182 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300183 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 _start = new char[ len+1 ];
185 memcpy( _start, str, len+1 );
186 _end = _start + len;
187 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800188}
189
190
191char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700193 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400195 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 char endChar = *endTag;
197 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // Inner loop of text parsing.
200 while ( *p ) {
201 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
202 Set( start, p, strFlags );
203 return p + length;
204 }
205 ++p;
206 }
207 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800208}
209
210
211char* StrPair::ParseName( char* p )
212{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400213 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700214 return 0;
215 }
JayXonee525db2014-12-24 04:01:42 -0500216 if ( !XMLUtil::IsNameStartChar( *p ) ) {
217 return 0;
218 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800219
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500221 ++p;
222 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700223 ++p;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
JayXonee525db2014-12-24 04:01:42 -0500226 Set( start, p, 0 );
227 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800228}
229
230
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700231void StrPair::CollapseWhitespace()
232{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400233 // Adjusting _start would cause undefined behavior on delete[]
234 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700235 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700236 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300238 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700239 char* p = _start; // the read pointer
240 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700241
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 while( *p ) {
243 if ( XMLUtil::IsWhiteSpace( *p )) {
244 p = XMLUtil::SkipWhiteSpace( p );
245 if ( *p == 0 ) {
246 break; // don't write to q; this trims the trailing space.
247 }
248 *q = ' ';
249 ++q;
250 }
251 *q = *p;
252 ++q;
253 ++p;
254 }
255 *q = 0;
256 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700257}
258
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800259
Lee Thomasone4422302012-01-20 17:59:50 -0800260const char* StrPair::GetStr()
261{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300262 TIXMLASSERT( _start );
263 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 if ( _flags & NEEDS_FLUSH ) {
265 *_end = 0;
266 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800267
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 if ( _flags ) {
269 char* p = _start; // the read pointer
270 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800271
Lee Thomason120b3a62012-10-12 10:06:59 -0700272 while( p < _end ) {
273 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700274 // CR-LF pair becomes LF
275 // CR alone becomes LF
276 // LF-CR becomes LF
277 if ( *(p+1) == LF ) {
278 p += 2;
279 }
280 else {
281 ++p;
282 }
283 *q++ = LF;
284 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700285 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700286 if ( *(p+1) == CR ) {
287 p += 2;
288 }
289 else {
290 ++p;
291 }
292 *q++ = LF;
293 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700294 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 // Entities handled by tinyXML2:
296 // - special entities in the entity table [in/out]
297 // - numeric character reference [in]
298 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800299
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400301 const int buflen = 10;
302 char buf[buflen] = { 0 };
303 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300304 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
305 if ( adjusted == 0 ) {
306 *q = *p;
307 ++p;
308 ++q;
309 }
310 else {
311 TIXMLASSERT( 0 <= len && len <= buflen );
312 TIXMLASSERT( q + len <= adjusted );
313 p = adjusted;
314 memcpy( q, buf, len );
315 q += len;
316 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700317 }
318 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300319 bool entityFound = false;
320 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400321 const Entity& entity = entities[i];
322 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
323 && *( p + entity.length + 1 ) == ';' ) {
324 // Found an entity - convert.
325 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400327 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 break;
330 }
331 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300332 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 // fixme: treat as error?
334 ++p;
335 ++q;
336 }
337 }
338 }
339 else {
340 *q = *p;
341 ++p;
342 ++q;
343 }
344 }
345 *q = 0;
346 }
347 // The loop below has plenty going on, and this
348 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300349 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700350 CollapseWhitespace();
351 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700352 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300354 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700355 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800356}
357
Lee Thomason2c85a712012-01-31 08:24:24 -0800358
Lee Thomasone4422302012-01-20 17:59:50 -0800359
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800360
Lee Thomason56bdd022012-02-09 18:16:58 -0800361// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800362
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800363const char* XMLUtil::ReadBOM( const char* p, bool* bom )
364{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300365 TIXMLASSERT( p );
366 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 *bom = false;
368 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
369 // Check for BOM:
370 if ( *(pu+0) == TIXML_UTF_LEAD_0
371 && *(pu+1) == TIXML_UTF_LEAD_1
372 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
373 *bom = true;
374 p += 3;
375 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300376 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800378}
379
380
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 const unsigned long BYTE_MASK = 0xBF;
384 const unsigned long BYTE_MARK = 0x80;
385 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 if (input < 0x80) {
388 *length = 1;
389 }
390 else if ( input < 0x800 ) {
391 *length = 2;
392 }
393 else if ( input < 0x10000 ) {
394 *length = 3;
395 }
396 else if ( input < 0x200000 ) {
397 *length = 4;
398 }
399 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300400 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700401 return;
402 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 // Scary scary fall throughs.
407 switch (*length) {
408 case 4:
409 --output;
410 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
411 input >>= 6;
412 case 3:
413 --output;
414 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
415 input >>= 6;
416 case 2:
417 --output;
418 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
419 input >>= 6;
420 case 1:
421 --output;
422 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100423 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300424 default:
425 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427}
428
429
430const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700432 // Presume an entity, and pull it out.
433 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800434
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 if ( *(p+1) == '#' && *(p+2) ) {
436 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300437 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 ptrdiff_t delta = 0;
439 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800440 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800441
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 if ( *(p+2) == 'x' ) {
443 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300444 const char* q = p+3;
445 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 return 0;
447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448
Lee Thomason7e67bc82015-01-12 14:05:12 -0800449 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800450
Dmitry-Me9f56e122015-01-12 10:07:54 +0300451 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 return 0;
453 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800454 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 delta = q-p;
457 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700460 unsigned int digit = 0;
461
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300463 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 }
465 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300466 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 }
468 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300469 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 }
471 else {
472 return 0;
473 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100474 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300475 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
476 const unsigned int digitScaled = mult * digit;
477 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
478 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300479 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 mult *= 16;
481 --q;
482 }
483 }
484 else {
485 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300486 const char* q = p+2;
487 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 return 0;
489 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800490
Lee Thomason7e67bc82015-01-12 14:05:12 -0800491 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800492
Dmitry-Me9f56e122015-01-12 10:07:54 +0300493 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 return 0;
495 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800496 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800497
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700498 delta = q-p;
499 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 while ( *q != '#' ) {
502 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300503 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100504 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300505 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
506 const unsigned int digitScaled = mult * digit;
507 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
508 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 }
510 else {
511 return 0;
512 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300513 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 mult *= 10;
515 --q;
516 }
517 }
518 // convert the UCS to UTF-8
519 ConvertUTF32ToUTF8( ucs, value, length );
520 return p + delta + 1;
521 }
522 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800524
525
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700526void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700529}
530
531
532void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700535}
536
537
538void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700541}
542
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800543/*
544 ToStr() of a number is a very tricky topic.
545 https://github.com/leethomason/tinyxml2/issues/106
546*/
Lee Thomason21be8822012-07-15 17:27:22 -0700547void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
548{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800549 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
554{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800555 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
Lee Thomason51c12712016-06-04 20:18:49 -0700559void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
560{
561 TIXML_SNPRINTF(buffer, bufferSize, "%lld", v);
562}
563
564
Lee Thomason21be8822012-07-15 17:27:22 -0700565bool XMLUtil::ToInt( const char* str, int* value )
566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
568 return true;
569 }
570 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
576 return true;
577 }
578 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700579}
580
581bool XMLUtil::ToBool( const char* str, bool* value )
582{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 int ival = 0;
584 if ( ToInt( str, &ival )) {
585 *value = (ival==0) ? false : true;
586 return true;
587 }
588 if ( StringEqual( str, "true" ) ) {
589 *value = true;
590 return true;
591 }
592 else if ( StringEqual( str, "false" ) ) {
593 *value = false;
594 return true;
595 }
596 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700597}
598
599
600bool XMLUtil::ToFloat( const char* str, float* value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
Lee Thomason51c12712016-06-04 20:18:49 -0700608
Lee Thomason21be8822012-07-15 17:27:22 -0700609bool XMLUtil::ToDouble( const char* str, double* value )
610{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
612 return true;
613 }
614 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700615}
616
617
Lee Thomason51c12712016-06-04 20:18:49 -0700618bool XMLUtil::ToInt64(const char* str, int64_t* value)
619{
620 if (TIXML_SSCANF(str, "%lld", value) == 1) {
621 return true;
622 }
623 return false;
624}
625
626
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700627char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800628{
Dmitry-Me02384662015-03-03 16:02:13 +0300629 TIXMLASSERT( node );
630 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400631 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300633 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300634 *node = 0;
635 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 return p;
637 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800638
Dmitry-Me962083b2015-05-26 11:38:30 +0300639 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 static const char* xmlHeader = { "<?" };
641 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300643 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800645
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const int xmlHeaderLen = 2;
647 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300649 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
653 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400654 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300656 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
658 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 p += xmlHeaderLen;
660 }
661 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300662 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 returnNode = new (_commentPool.Alloc()) XMLComment( this );
664 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 p += commentHeaderLen;
666 }
667 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 p += cdataHeaderLen;
673 text->SetCData( true );
674 }
675 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300676 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
678 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 p += dtdHeaderLen;
680 }
681 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300682 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 returnNode = new (_elementPool.Alloc()) XMLElement( this );
684 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 p += elementHeaderLen;
686 }
687 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300688 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 returnNode = new (_textPool.Alloc()) XMLText( this );
690 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 p = start; // Back it up, all the text counts.
692 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693
Dmitry-Me02384662015-03-03 16:02:13 +0300694 TIXMLASSERT( returnNode );
695 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 *node = returnNode;
697 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698}
699
700
Lee Thomason751da522012-02-10 08:50:51 -0800701bool XMLDocument::Accept( XMLVisitor* visitor ) const
702{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300703 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 if ( visitor->VisitEnter( *this ) ) {
705 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
706 if ( !node->Accept( visitor ) ) {
707 break;
708 }
709 }
710 }
711 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800712}
Lee Thomason56bdd022012-02-09 18:16:58 -0800713
714
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800715// --------- XMLNode ----------- //
716
717XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 _document( doc ),
719 _parent( 0 ),
720 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200721 _prev( 0 ), _next( 0 ),
722 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800724}
725
726
727XMLNode::~XMLNode()
728{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 if ( _parent ) {
731 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800733}
734
Michael Daumling21626882013-10-22 17:03:37 +0200735const char* XMLNode::Value() const
736{
Lee Thomason85492022015-05-22 11:07:45 -0700737 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530738 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530739 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200740 return _value.GetStr();
741}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800742
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800743void XMLNode::SetValue( const char* str, bool staticMem )
744{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700745 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 }
748 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800751}
752
753
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800754void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755{
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300757 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300758 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700761
Dmitry-Mee3225b12014-09-03 11:03:11 +0400762 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800765}
766
767
768void XMLNode::Unlink( XMLNode* child )
769{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300770 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300771 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300772 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 if ( child == _firstChild ) {
774 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 if ( child == _lastChild ) {
777 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
Lee Thomasond923c672012-01-23 08:44:25 -0800779
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( child->_prev ) {
781 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 if ( child->_next ) {
784 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700786 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800787}
788
789
U-Stream\Leeae25a442012-02-17 17:48:16 -0800790void XMLNode::DeleteChild( XMLNode* node )
791{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300792 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300793 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100795 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400796 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800797}
798
799
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800800XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
801{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300802 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300803 if ( addThis->_document != _document ) {
804 TIXMLASSERT( false );
805 return 0;
806 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800807 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700808
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( _lastChild ) {
810 TIXMLASSERT( _firstChild );
811 TIXMLASSERT( _lastChild->_next == 0 );
812 _lastChild->_next = addThis;
813 addThis->_prev = _lastChild;
814 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800815
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
818 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 TIXMLASSERT( _firstChild == 0 );
820 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800821
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 addThis->_prev = 0;
823 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800827}
828
829
Lee Thomason1ff38e02012-02-14 18:18:16 -0800830XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
831{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300832 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300833 if ( addThis->_document != _document ) {
834 TIXMLASSERT( false );
835 return 0;
836 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800837 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 if ( _firstChild ) {
840 TIXMLASSERT( _lastChild );
841 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800842
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 _firstChild->_prev = addThis;
844 addThis->_next = _firstChild;
845 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 }
849 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 TIXMLASSERT( _lastChild == 0 );
851 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800852
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 addThis->_prev = 0;
854 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400857 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800858}
859
860
861XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
862{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300863 TIXMLASSERT( addThis );
864 if ( addThis->_document != _document ) {
865 TIXMLASSERT( false );
866 return 0;
867 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700868
Dmitry-Meabb2d042014-12-09 12:59:31 +0300869 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700870
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300872 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 return 0;
874 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 // The last node or the only node.
878 return InsertEndChild( addThis );
879 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800880 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 addThis->_prev = afterThis;
882 addThis->_next = afterThis->_next;
883 afterThis->_next->_prev = addThis;
884 afterThis->_next = addThis;
885 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887}
888
889
890
891
Dmitry-Me886ad972015-07-22 11:00:51 +0300892const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800893{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300894 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
895 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300897 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 return element;
899 }
900 }
901 }
902 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800903}
904
905
Dmitry-Me886ad972015-07-22 11:00:51 +0300906const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800907{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300908 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
909 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700910 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300911 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 return element;
913 }
914 }
915 }
916 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800917}
918
919
Dmitry-Me886ad972015-07-22 11:00:51 +0300920const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800921{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300922 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400923 const XMLElement* element = node->ToElement();
924 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300925 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400936 const XMLElement* element = node->ToElement();
937 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300938 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800943}
944
945
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800946char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 // This is a recursive method, but thinking about it "at the current level"
949 // it is a pretty simple flat list:
950 // <foo/>
951 // <!-- comment -->
952 //
953 // With a special case:
954 // <foo>
955 // </foo>
956 // <!-- comment -->
957 //
958 // Where the closing element (/foo) *must* be the next thing after the opening
959 // element, and the names must match. BUT the tricky bit is that the closing
960 // element will be read by the child.
961 //
962 // 'endTag' is the end tag for this node, it is returned by a call to a child.
963 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 while( p && *p ) {
966 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800967
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300969 if ( node == 0 ) {
970 break;
971 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 StrPair endTag;
974 p = node->ParseDeep( p, &endTag );
975 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400976 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700977 if ( !_document->Error() ) {
978 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
980 break;
981 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800982
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530983 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530984 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530985 // A declaration can only be the first child of a document.
986 // Set error, if document already has children.
987 if ( !_document->NoChildren() ) {
988 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
989 DeleteNode( decl );
990 break;
991 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530992 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530993
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400994 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500996 // We read the end tag. Return it to the parent.
997 if ( ele->ClosingType() == XMLElement::CLOSING ) {
998 if ( parentEnd ) {
999 ele->_value.TransferTo( parentEnd );
1000 }
1001 node->_memPool->SetTracked(); // created and then immediately deleted.
1002 DeleteNode( node );
1003 return p;
1004 }
1005
1006 // Handle an end tag returned to this level.
1007 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001008 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001009 if ( endTag.Empty() ) {
1010 if ( ele->ClosingType() == XMLElement::OPEN ) {
1011 mismatch = true;
1012 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001014 else {
1015 if ( ele->ClosingType() != XMLElement::OPEN ) {
1016 mismatch = true;
1017 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001018 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001019 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 }
1021 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001022 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001023 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001024 DeleteNode( node );
1025 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001026 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 }
JayXondbfdd8f2014-12-12 20:07:14 -05001028 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 }
1030 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001031}
1032
Dmitry-Mee3225b12014-09-03 11:03:11 +04001033void XMLNode::DeleteNode( XMLNode* node )
1034{
1035 if ( node == 0 ) {
1036 return;
1037 }
1038 MemPool* pool = node->_memPool;
1039 node->~XMLNode();
1040 pool->Free( node );
1041}
1042
Lee Thomason3cebdc42015-01-05 17:16:28 -08001043void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001044{
1045 TIXMLASSERT( insertThis );
1046 TIXMLASSERT( insertThis->_document == _document );
1047
1048 if ( insertThis->_parent )
1049 insertThis->_parent->Unlink( insertThis );
1050 else
1051 insertThis->_memPool->SetTracked();
1052}
1053
Lee Thomason5492a1c2012-01-23 15:32:10 -08001054// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001055char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001056{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 const char* start = p;
1058 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001059 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001061 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 }
1063 return p;
1064 }
1065 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001066 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1067 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001068 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001070
Lee Thomason624d43f2012-10-12 10:58:48 -07001071 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 if ( p && *p ) {
1073 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001074 }
1075 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001076 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 }
1078 }
1079 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001080}
1081
1082
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001083XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 }
1088 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1089 text->SetCData( this->CData() );
1090 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001091}
1092
1093
1094bool XMLText::ShallowEqual( const XMLNode* compare ) const
1095{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001096 const XMLText* text = compare->ToText();
1097 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001098}
1099
1100
Lee Thomason56bdd022012-02-09 18:16:58 -08001101bool XMLText::Accept( XMLVisitor* visitor ) const
1102{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001103 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001105}
1106
1107
Lee Thomason3f57d272012-01-11 15:30:03 -08001108// --------- XMLComment ---------- //
1109
Lee Thomasone4422302012-01-20 17:59:50 -08001110XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001111{
1112}
1113
1114
Lee Thomasonce0763e2012-01-11 15:43:54 -08001115XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001116{
Lee Thomason3f57d272012-01-11 15:30:03 -08001117}
1118
1119
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001120char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 // Comment parses as text.
1123 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001124 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001129}
1130
1131
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001132XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 }
1137 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1138 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001139}
1140
1141
1142bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1143{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001144 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001145 const XMLComment* comment = compare->ToComment();
1146 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001147}
1148
1149
Lee Thomason751da522012-02-10 08:50:51 -08001150bool XMLComment::Accept( XMLVisitor* visitor ) const
1151{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001152 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001154}
Lee Thomason56bdd022012-02-09 18:16:58 -08001155
1156
Lee Thomason50f97b22012-02-11 16:33:40 -08001157// --------- XMLDeclaration ---------- //
1158
1159XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1160{
1161}
1162
1163
1164XMLDeclaration::~XMLDeclaration()
1165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001167}
1168
1169
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001170char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 // Declaration parses as text.
1173 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001174 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001176 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 }
1178 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001179}
1180
1181
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001182XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001185 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 }
1187 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1188 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001189}
1190
1191
1192bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1193{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001194 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001195 const XMLDeclaration* declaration = compare->ToDeclaration();
1196 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001197}
1198
1199
1200
Lee Thomason50f97b22012-02-11 16:33:40 -08001201bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1202{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001203 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001205}
1206
1207// --------- XMLUnknown ---------- //
1208
1209XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1210{
1211}
1212
1213
1214XMLUnknown::~XMLUnknown()
1215{
1216}
1217
1218
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001219char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 // Unknown parses as text.
1222 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001223
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001226 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 }
1228 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001229}
1230
1231
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001232XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001235 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 }
1237 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1238 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001239}
1240
1241
1242bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1243{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001244 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001245 const XMLUnknown* unknown = compare->ToUnknown();
1246 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001247}
1248
1249
Lee Thomason50f97b22012-02-11 16:33:40 -08001250bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1251{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001252 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001254}
1255
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001256// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001257
1258const char* XMLAttribute::Name() const
1259{
1260 return _name.GetStr();
1261}
1262
1263const char* XMLAttribute::Value() const
1264{
1265 return _value.GetStr();
1266}
1267
Lee Thomason6f381b72012-03-02 12:59:39 -08001268char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001271 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 if ( !p || !*p ) {
1273 return 0;
1274 }
Lee Thomason22aead12012-01-23 13:29:35 -08001275
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 // Skip white space before =
1277 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001278 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 return 0;
1280 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001281
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 ++p; // move up to opening quote
1283 p = XMLUtil::SkipWhiteSpace( p );
1284 if ( *p != '\"' && *p != '\'' ) {
1285 return 0;
1286 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001287
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 char endTag[2] = { *p, 0 };
1289 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001290
Lee Thomason624d43f2012-10-12 10:58:48 -07001291 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001293}
1294
1295
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001296void XMLAttribute::SetName( const char* n )
1297{
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001299}
1300
1301
Lee Thomason2fa81722012-11-09 12:37:46 -08001302XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001305 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 }
1307 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001308}
1309
1310
Lee Thomason2fa81722012-11-09 12:37:46 -08001311XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001314 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 }
1316 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001317}
1318
1319
Lee Thomason51c12712016-06-04 20:18:49 -07001320XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1321{
1322 if (XMLUtil::ToInt64(Value(), value)) {
1323 return XML_SUCCESS;
1324 }
1325 return XML_WRONG_ATTRIBUTE_TYPE;
1326}
1327
1328
Lee Thomason2fa81722012-11-09 12:37:46 -08001329XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001332 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 }
1334 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001335}
1336
1337
Lee Thomason2fa81722012-11-09 12:37:46 -08001338XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001341 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 }
1343 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001344}
1345
1346
Lee Thomason2fa81722012-11-09 12:37:46 -08001347XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001350 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 }
1352 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001353}
1354
1355
1356void XMLAttribute::SetAttribute( const char* v )
1357{
Lee Thomason624d43f2012-10-12 10:58:48 -07001358 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001359}
1360
1361
Lee Thomason1ff38e02012-02-14 18:18:16 -08001362void XMLAttribute::SetAttribute( int v )
1363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 char buf[BUF_SIZE];
1365 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001366 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001367}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001368
1369
1370void XMLAttribute::SetAttribute( unsigned v )
1371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 char buf[BUF_SIZE];
1373 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001374 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001375}
1376
1377
Lee Thomason51c12712016-06-04 20:18:49 -07001378void XMLAttribute::SetAttribute(int64_t v)
1379{
1380 char buf[BUF_SIZE];
1381 XMLUtil::ToStr(v, buf, BUF_SIZE);
1382 _value.SetStr(buf);
1383}
1384
1385
1386
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001387void XMLAttribute::SetAttribute( bool v )
1388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 char buf[BUF_SIZE];
1390 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001391 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001392}
1393
1394void XMLAttribute::SetAttribute( double v )
1395{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 char buf[BUF_SIZE];
1397 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001399}
1400
1401void XMLAttribute::SetAttribute( float v )
1402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 char buf[BUF_SIZE];
1404 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001405 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001406}
1407
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001408
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001409// --------- XMLElement ---------- //
1410XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001411 _closingType( 0 ),
1412 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001413{
1414}
1415
1416
1417XMLElement::~XMLElement()
1418{
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 while( _rootAttribute ) {
1420 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001421 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001424}
1425
1426
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1428{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001429 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1431 return a;
1432 }
1433 }
1434 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001435}
1436
1437
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001438const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 const XMLAttribute* a = FindAttribute( name );
1441 if ( !a ) {
1442 return 0;
1443 }
1444 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1445 return a->Value();
1446 }
1447 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001448}
1449
1450
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001451const char* XMLElement::GetText() const
1452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001454 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
1456 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001457}
1458
1459
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001460void XMLElement::SetText( const char* inText )
1461{
Uli Kusterer869bb592014-01-21 01:36:16 +01001462 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001463 FirstChild()->SetValue( inText );
1464 else {
1465 XMLText* theText = GetDocument()->NewText( inText );
1466 InsertFirstChild( theText );
1467 }
1468}
1469
Lee Thomason5bb2d802014-01-24 10:42:57 -08001470
1471void XMLElement::SetText( int v )
1472{
1473 char buf[BUF_SIZE];
1474 XMLUtil::ToStr( v, buf, BUF_SIZE );
1475 SetText( buf );
1476}
1477
1478
1479void XMLElement::SetText( unsigned v )
1480{
1481 char buf[BUF_SIZE];
1482 XMLUtil::ToStr( v, buf, BUF_SIZE );
1483 SetText( buf );
1484}
1485
1486
Lee Thomason51c12712016-06-04 20:18:49 -07001487void XMLElement::SetText(int64_t v)
1488{
1489 char buf[BUF_SIZE];
1490 XMLUtil::ToStr(v, buf, BUF_SIZE);
1491 SetText(buf);
1492}
1493
1494
1495void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001496{
1497 char buf[BUF_SIZE];
1498 XMLUtil::ToStr( v, buf, BUF_SIZE );
1499 SetText( buf );
1500}
1501
1502
1503void XMLElement::SetText( float v )
1504{
1505 char buf[BUF_SIZE];
1506 XMLUtil::ToStr( v, buf, BUF_SIZE );
1507 SetText( buf );
1508}
1509
1510
1511void XMLElement::SetText( double v )
1512{
1513 char buf[BUF_SIZE];
1514 XMLUtil::ToStr( v, buf, BUF_SIZE );
1515 SetText( buf );
1516}
1517
1518
MortenMacFly4ee49f12013-01-14 20:03:14 +01001519XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001522 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001523 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 return XML_SUCCESS;
1525 }
1526 return XML_CAN_NOT_CONVERT_TEXT;
1527 }
1528 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001529}
1530
1531
MortenMacFly4ee49f12013-01-14 20:03:14 +01001532XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001535 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001536 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 return XML_SUCCESS;
1538 }
1539 return XML_CAN_NOT_CONVERT_TEXT;
1540 }
1541 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001542}
1543
1544
Lee Thomason51c12712016-06-04 20:18:49 -07001545XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1546{
1547 if (FirstChild() && FirstChild()->ToText()) {
1548 const char* t = FirstChild()->Value();
1549 if (XMLUtil::ToInt64(t, ival)) {
1550 return XML_SUCCESS;
1551 }
1552 return XML_CAN_NOT_CONVERT_TEXT;
1553 }
1554 return XML_NO_TEXT_NODE;
1555}
1556
1557
MortenMacFly4ee49f12013-01-14 20:03:14 +01001558XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001561 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001562 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 return XML_SUCCESS;
1564 }
1565 return XML_CAN_NOT_CONVERT_TEXT;
1566 }
1567 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001568}
1569
1570
MortenMacFly4ee49f12013-01-14 20:03:14 +01001571XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001574 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001575 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 return XML_SUCCESS;
1577 }
1578 return XML_CAN_NOT_CONVERT_TEXT;
1579 }
1580 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001581}
1582
1583
MortenMacFly4ee49f12013-01-14 20:03:14 +01001584XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001585{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001587 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001588 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 return XML_SUCCESS;
1590 }
1591 return XML_CAN_NOT_CONVERT_TEXT;
1592 }
1593 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001594}
1595
1596
1597
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001598XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1599{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 XMLAttribute* last = 0;
1601 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001602 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1606 break;
1607 }
1608 }
1609 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001610 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1612 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 }
1616 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001620 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001623}
1624
1625
U-Stream\Leeae25a442012-02-17 17:48:16 -08001626void XMLElement::DeleteAttribute( const char* name )
1627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1631 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 }
1634 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001637 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 break;
1639 }
1640 prev = a;
1641 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001642}
1643
1644
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001645char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001646{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 const char* start = p;
1648 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001649
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 // Read the attributes.
1651 while( p ) {
1652 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001653 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 return 0;
1656 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001657
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001659 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001660 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1662 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001663 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001664
Lee Thomason624d43f2012-10-12 10:58:48 -07001665 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001667 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 return 0;
1670 }
1671 // There is a minor bug here: if the attribute in the source xml
1672 // document is duplicated, it will not be detected and the
1673 // attribute will be doubly added. However, tracking the 'prevAttribute'
1674 // avoids re-scanning the attribute list. Preferring performance for
1675 // now, may reconsider in the future.
1676 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 }
1679 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 }
1682 prevAttribute = attrib;
1683 }
1684 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 else if ( *p == '>' ) {
1686 ++p;
1687 break;
1688 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001689 // end of the tag
1690 else if ( *p == '/' && *(p+1) == '>' ) {
1691 _closingType = CLOSED;
1692 return p+2; // done; sealed element.
1693 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 return 0;
1697 }
1698 }
1699 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001700}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001701
Dmitry-Mee3225b12014-09-03 11:03:11 +04001702void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1703{
1704 if ( attribute == 0 ) {
1705 return;
1706 }
1707 MemPool* pool = attribute->_memPool;
1708 attribute->~XMLAttribute();
1709 pool->Free( attribute );
1710}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001711
Lee Thomason67d61312012-01-24 16:01:51 -08001712//
1713// <ele></ele>
1714// <ele>foo<b>bar</b></ele>
1715//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001716char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001717{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 // Read the element name.
1719 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001720
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 // The closing element is the </element> form. It is
1722 // parsed just like a regular element then deleted from
1723 // the DOM.
1724 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 ++p;
1727 }
Lee Thomason67d61312012-01-24 16:01:51 -08001728
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 p = _value.ParseName( p );
1730 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 return 0;
1732 }
Lee Thomason67d61312012-01-24 16:01:51 -08001733
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 return p;
1737 }
Lee Thomason67d61312012-01-24 16:01:51 -08001738
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 p = XMLNode::ParseDeep( p, strPair );
1740 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001741}
1742
1743
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001744
1745XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1746{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 }
1750 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1751 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1752 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1753 }
1754 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001755}
1756
1757
1758bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1759{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001760 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001762 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001763
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 const XMLAttribute* a=FirstAttribute();
1765 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 while ( a && b ) {
1768 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1769 return false;
1770 }
1771 a = a->Next();
1772 b = b->Next();
1773 }
1774 if ( a || b ) {
1775 // different count
1776 return false;
1777 }
1778 return true;
1779 }
1780 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001781}
1782
1783
Lee Thomason751da522012-02-10 08:50:51 -08001784bool XMLElement::Accept( XMLVisitor* visitor ) const
1785{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001786 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1789 if ( !node->Accept( visitor ) ) {
1790 break;
1791 }
1792 }
1793 }
1794 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001795}
Lee Thomason56bdd022012-02-09 18:16:58 -08001796
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001797
Lee Thomason3f57d272012-01-11 15:30:03 -08001798// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001799
1800// Warning: List must match 'enum XMLError'
1801const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1802 "XML_SUCCESS",
1803 "XML_NO_ATTRIBUTE",
1804 "XML_WRONG_ATTRIBUTE_TYPE",
1805 "XML_ERROR_FILE_NOT_FOUND",
1806 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1807 "XML_ERROR_FILE_READ_ERROR",
1808 "XML_ERROR_ELEMENT_MISMATCH",
1809 "XML_ERROR_PARSING_ELEMENT",
1810 "XML_ERROR_PARSING_ATTRIBUTE",
1811 "XML_ERROR_IDENTIFYING_TAG",
1812 "XML_ERROR_PARSING_TEXT",
1813 "XML_ERROR_PARSING_CDATA",
1814 "XML_ERROR_PARSING_COMMENT",
1815 "XML_ERROR_PARSING_DECLARATION",
1816 "XML_ERROR_PARSING_UNKNOWN",
1817 "XML_ERROR_EMPTY_DOCUMENT",
1818 "XML_ERROR_MISMATCHED_ELEMENT",
1819 "XML_ERROR_PARSING",
1820 "XML_CAN_NOT_CONVERT_TEXT",
1821 "XML_NO_TEXT_NODE"
1822};
1823
1824
Lee Thomason624d43f2012-10-12 10:58:48 -07001825XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 _writeBOM( false ),
1828 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001829 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _whitespace( whitespace ),
1831 _errorStr1( 0 ),
1832 _errorStr2( 0 ),
1833 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001834{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001835 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1836 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001837}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001838
1839
Lee Thomason3f57d272012-01-11 15:30:03 -08001840XMLDocument::~XMLDocument()
1841{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001842 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001843}
1844
1845
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001846void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001847{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001848 DeleteChildren();
1849
Dmitry-Meab37df82014-11-28 12:08:36 +03001850#ifdef DEBUG
1851 const bool hadError = Error();
1852#endif
Lee Thomason85536252016-06-04 19:10:53 -07001853 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _errorStr1 = 0;
1855 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001856
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 delete [] _charBuffer;
1858 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001859
1860#if 0
1861 _textPool.Trace( "text" );
1862 _elementPool.Trace( "element" );
1863 _commentPool.Trace( "comment" );
1864 _attributePool.Trace( "attribute" );
1865#endif
1866
1867#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001868 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001869 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1870 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1871 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1872 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1873 }
1874#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001875}
1876
Lee Thomason3f57d272012-01-11 15:30:03 -08001877
Lee Thomason2c85a712012-01-31 08:24:24 -08001878XMLElement* XMLDocument::NewElement( const char* name )
1879{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001880 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1882 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 ele->SetName( name );
1884 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001885}
1886
1887
Lee Thomason1ff38e02012-02-14 18:18:16 -08001888XMLComment* XMLDocument::NewComment( const char* str )
1889{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001890 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1892 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 comment->SetValue( str );
1894 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001895}
1896
1897
1898XMLText* XMLDocument::NewText( const char* str )
1899{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001900 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1902 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 text->SetValue( str );
1904 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001905}
1906
1907
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001908XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1909{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001910 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1912 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1914 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001915}
1916
1917
1918XMLUnknown* XMLDocument::NewUnknown( const char* str )
1919{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001920 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1922 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 unk->SetValue( str );
1924 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001925}
1926
Dmitry-Me01578db2014-08-19 10:18:48 +04001927static FILE* callfopen( const char* filepath, const char* mode )
1928{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001929 TIXMLASSERT( filepath );
1930 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001931#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1932 FILE* fp = 0;
1933 errno_t err = fopen_s( &fp, filepath, mode );
1934 if ( err ) {
1935 return 0;
1936 }
1937#else
1938 FILE* fp = fopen( filepath, mode );
1939#endif
1940 return fp;
1941}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001942
1943void XMLDocument::DeleteNode( XMLNode* node ) {
1944 TIXMLASSERT( node );
1945 TIXMLASSERT(node->_document == this );
1946 if (node->_parent) {
1947 node->_parent->DeleteChild( node );
1948 }
1949 else {
1950 // Isn't in the tree.
1951 // Use the parent delete.
1952 // Also, we need to mark it tracked: we 'know'
1953 // it was never used.
1954 node->_memPool->SetTracked();
1955 // Call the static XMLNode version:
1956 XMLNode::DeleteNode(node);
1957 }
1958}
1959
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001960
Lee Thomason2fa81722012-11-09 12:37:46 -08001961XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001962{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001963 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001964 FILE* fp = callfopen( filename, "rb" );
1965 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
1969 LoadFile( fp );
1970 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001972}
1973
Dmitry-Me901fed52015-09-25 10:29:51 +03001974// This is likely overengineered template art to have a check that unsigned long value incremented
1975// by one still fits into size_t. If size_t type is larger than unsigned long type
1976// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1977// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1978// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1979// types sizes relate to each other.
1980template
1981<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1982struct LongFitsIntoSizeTMinusOne {
1983 static bool Fits( unsigned long value )
1984 {
1985 return value < (size_t)-1;
1986 }
1987};
1988
1989template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001990struct LongFitsIntoSizeTMinusOne<false> {
1991 static bool Fits( unsigned long )
1992 {
1993 return true;
1994 }
1995};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001996
Lee Thomason2fa81722012-11-09 12:37:46 -08001997XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001998{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001999 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002000
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002001 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002002 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002003 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2004 return _errorID;
2005 }
2006
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002008 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002010 if ( filelength == -1L ) {
2011 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2012 return _errorID;
2013 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002014 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002015
Dmitry-Me901fed52015-09-25 10:29:51 +03002016 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002017 // Cannot handle files which won't fit in buffer together with null terminator
2018 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2019 return _errorID;
2020 }
2021
Dmitry-Me72801b82015-05-07 09:41:39 +03002022 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002023 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002026
Dmitry-Me72801b82015-05-07 09:41:39 +03002027 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002028 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 _charBuffer = new char[size+1];
2030 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 if ( read != size ) {
2032 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002035
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002037
Dmitry-Me97476b72015-01-01 16:15:57 +03002038 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002040}
2041
2042
Lee Thomason2fa81722012-11-09 12:37:46 -08002043XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002044{
Dmitry-Me01578db2014-08-19 10:18:48 +04002045 FILE* fp = callfopen( filename, "w" );
2046 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 }
2050 SaveFile(fp, compact);
2051 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002053}
2054
2055
Lee Thomason2fa81722012-11-09 12:37:46 -08002056XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002057{
Ant Mitchell189198f2015-03-24 16:20:36 +00002058 // Clear any error from the last save, otherwise it will get reported
2059 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002060 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 XMLPrinter stream( fp, compact );
2062 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002064}
2065
Lee Thomason1ff38e02012-02-14 18:18:16 -08002066
Lee Thomason2fa81722012-11-09 12:37:46 -08002067XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002068{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002069 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002070
Lee Thomason82d32002014-02-21 22:47:18 -08002071 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 }
2075 if ( len == (size_t)(-1) ) {
2076 len = strlen( p );
2077 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002078 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 _charBuffer = new char[ len+1 ];
2080 memcpy( _charBuffer, p, len );
2081 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002082
Dmitry-Me97476b72015-01-01 16:15:57 +03002083 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002084 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002085 // clean up now essentially dangling memory.
2086 // and the parse fail can put objects in the
2087 // pools that are dead and inaccessible.
2088 DeleteChildren();
2089 _elementPool.Clear();
2090 _attributePool.Clear();
2091 _textPool.Clear();
2092 _commentPool.Clear();
2093 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002095}
2096
2097
PKEuS1c5f99e2013-07-06 11:28:39 +02002098void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002099{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002100 if ( streamer ) {
2101 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002103 else {
2104 XMLPrinter stdoutStreamer( stdout );
2105 Accept( &stdoutStreamer );
2106 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002107}
2108
2109
Lee Thomason2fa81722012-11-09 12:37:46 -08002110void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002111{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002112 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 _errorID = error;
2114 _errorStr1 = str1;
2115 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002116}
2117
Lee Thomason331596e2014-09-11 14:56:43 -07002118const char* XMLDocument::ErrorName() const
2119{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002120 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002121 const char* errorName = _errorNames[_errorID];
2122 TIXMLASSERT( errorName && errorName[0] );
2123 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002124}
Lee Thomason5cae8972012-01-24 18:03:07 -08002125
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002126void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002127{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002128 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 static const int LEN = 20;
2130 char buf1[LEN] = { 0 };
2131 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002132
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 if ( _errorStr1 ) {
2134 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 if ( _errorStr2 ) {
2137 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002139
Dmitry-Me2ad43202015-04-16 12:18:58 +03002140 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2141 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2142 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002143 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002144 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146}
2147
Dmitry-Me97476b72015-01-01 16:15:57 +03002148void XMLDocument::Parse()
2149{
2150 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2151 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002152 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002153 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002154 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002155 if ( !*p ) {
2156 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2157 return;
2158 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002159 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002160}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002161
PKEuS1bfb9542013-08-04 13:51:17 +02002162XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 _elementJustOpened( false ),
2164 _firstElement( true ),
2165 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002166 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 _textDepth( -1 ),
2168 _processEntities( true ),
2169 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _entityFlag[i] = false;
2173 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 }
2175 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002176 const char entityValue = entities[i].value;
2177 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2178 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002180 _restrictedEntityFlag[(unsigned char)'&'] = true;
2181 _restrictedEntityFlag[(unsigned char)'<'] = true;
2182 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002184}
2185
2186
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002187void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002188{
2189 va_list va;
2190 va_start( va, format );
2191
Lee Thomason624d43f2012-10-12 10:58:48 -07002192 if ( _fp ) {
2193 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 }
2195 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002196 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 // Close out and re-start the va-args
2198 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002199 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002201 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002202 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002203 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002205 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002206}
2207
2208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 for( int i=0; i<depth; ++i ) {
2212 Print( " " );
2213 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002214}
2215
2216
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002217void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 // Look for runs of bytes between entities to print.
2220 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002221
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002223 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002225 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 // Remember, char is sometimes signed. (How many times has that bitten me?)
2227 if ( *q > 0 && *q < ENTITY_RANGE ) {
2228 // Check for entities. If one is found, flush
2229 // the stream up until the entity, write the
2230 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002231 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002233 const size_t delta = q - p;
2234 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002235 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002236 Print( "%.*s", toPrint, p );
2237 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002239 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 for( int i=0; i<NUM_ENTITIES; ++i ) {
2241 if ( entities[i].value == *q ) {
2242 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002243 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 break;
2245 }
2246 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002247 if ( !entityPatternPrinted ) {
2248 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2249 TIXMLASSERT( false );
2250 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 ++p;
2252 }
2253 }
2254 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002255 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
2257 }
2258 // Flush the remaining string. This will be the entire
2259 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002260 TIXMLASSERT( p <= q );
2261 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "%s", p );
2263 }
Lee Thomason857b8682012-01-25 17:50:25 -08002264}
2265
U-Stream\Leeae25a442012-02-17 17:48:16 -08002266
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002267void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002270 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 -07002271 Print( "%s", bom );
2272 }
2273 if ( writeDec ) {
2274 PushDeclaration( "xml version=\"1.0\"" );
2275 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002276}
2277
2278
Uli Kusterer593a33d2014-02-01 12:48:51 +01002279void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002280{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002281 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002282 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002283
Uli Kusterer593a33d2014-02-01 12:48:51 +01002284 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002286 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002287 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002290
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 _elementJustOpened = true;
2293 _firstElement = false;
2294 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002295}
2296
2297
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002298void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002299{
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 Print( " %s=\"", name );
2302 PrintString( value, false );
2303 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002304}
2305
2306
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002307void XMLPrinter::PushAttribute( const char* name, int v )
2308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 char buf[BUF_SIZE];
2310 XMLUtil::ToStr( v, buf, BUF_SIZE );
2311 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002312}
2313
2314
2315void XMLPrinter::PushAttribute( const char* name, unsigned v )
2316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 char buf[BUF_SIZE];
2318 XMLUtil::ToStr( v, buf, BUF_SIZE );
2319 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002320}
2321
2322
Lee Thomason51c12712016-06-04 20:18:49 -07002323void XMLPrinter::PushAttribute(const char* name, int64_t v)
2324{
2325 char buf[BUF_SIZE];
2326 XMLUtil::ToStr(v, buf, BUF_SIZE);
2327 PushAttribute(name, buf);
2328}
2329
2330
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002331void XMLPrinter::PushAttribute( const char* name, bool v )
2332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 char buf[BUF_SIZE];
2334 XMLUtil::ToStr( v, buf, BUF_SIZE );
2335 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002336}
2337
2338
2339void XMLPrinter::PushAttribute( const char* name, double v )
2340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 char buf[BUF_SIZE];
2342 XMLUtil::ToStr( v, buf, BUF_SIZE );
2343 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002344}
2345
2346
Uli Kustererca412e82014-02-01 13:35:05 +01002347void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002348{
Lee Thomason624d43f2012-10-12 10:58:48 -07002349 --_depth;
2350 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002351
Lee Thomason624d43f2012-10-12 10:58:48 -07002352 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 Print( "/>" );
2354 }
2355 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002356 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 }
2360 Print( "</%s>", name );
2361 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002362
Lee Thomason624d43f2012-10-12 10:58:48 -07002363 if ( _textDepth == _depth ) {
2364 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 }
Uli Kustererca412e82014-02-01 13:35:05 +01002366 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 Print( "\n" );
2368 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002370}
2371
2372
Dmitry-Mea092bc12014-12-23 17:57:05 +03002373void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002374{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002375 if ( !_elementJustOpened ) {
2376 return;
2377 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002380}
2381
2382
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002383void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002384{
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002386
Dmitry-Mea092bc12014-12-23 17:57:05 +03002387 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002389 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002390 }
2391 else {
2392 PrintString( text, true );
2393 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002394}
2395
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002396void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 char buf[BUF_SIZE];
2399 XMLUtil::ToStr( value, buf, BUF_SIZE );
2400 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002401}
2402
2403
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002404void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 char buf[BUF_SIZE];
2407 XMLUtil::ToStr( value, buf, BUF_SIZE );
2408 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002409}
2410
2411
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002412void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 char buf[BUF_SIZE];
2415 XMLUtil::ToStr( value, buf, BUF_SIZE );
2416 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002417}
2418
2419
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002420void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 char buf[BUF_SIZE];
2423 XMLUtil::ToStr( value, buf, BUF_SIZE );
2424 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002425}
2426
2427
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002428void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 char buf[BUF_SIZE];
2431 XMLUtil::ToStr( value, buf, BUF_SIZE );
2432 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002433}
2434
Lee Thomason5cae8972012-01-24 18:03:07 -08002435
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002436void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002437{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002438 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002439 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002443 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002444 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002445}
Lee Thomason751da522012-02-10 08:50:51 -08002446
2447
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002448void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002449{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002450 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002451 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002455 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002456 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002457}
2458
2459
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002460void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002461{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002462 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002463 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002467 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002469}
2470
2471
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002472bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002473{
Lee Thomason624d43f2012-10-12 10:58:48 -07002474 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 if ( doc.HasBOM() ) {
2476 PushHeader( true, false );
2477 }
2478 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002479}
2480
2481
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002482bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002483{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002484 const XMLElement* parentElem = 0;
2485 if ( element.Parent() ) {
2486 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002487 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002488 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002489 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 while ( attribute ) {
2491 PushAttribute( attribute->Name(), attribute->Value() );
2492 attribute = attribute->Next();
2493 }
2494 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002495}
2496
2497
Uli Kustererca412e82014-02-01 13:35:05 +01002498bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002499{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002500 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002502}
2503
2504
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002505bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 PushText( text.Value(), text.CData() );
2508 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002509}
2510
2511
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002512bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 PushComment( comment.Value() );
2515 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002516}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002517
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002518bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002519{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002520 PushDeclaration( declaration.Value() );
2521 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002522}
2523
2524
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002525bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002526{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 PushUnknown( unknown.Value() );
2528 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002529}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002530
Lee Thomason685b8952012-11-12 13:00:06 -08002531} // namespace tinyxml2
2532