blob: 7a804f5dd3b6f22ff718ad75cbd2b2cde03e9c52 [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 <>
1990bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1991{
1992 return true;
1993}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001994
Lee Thomason2fa81722012-11-09 12:37:46 -08001995XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001996{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001997 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001998
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001999 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002000 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002001 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2002 return _errorID;
2003 }
2004
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002006 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002008 if ( filelength == -1L ) {
2009 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2010 return _errorID;
2011 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002012 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002013
Dmitry-Me901fed52015-09-25 10:29:51 +03002014 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002015 // Cannot handle files which won't fit in buffer together with null terminator
2016 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2017 return _errorID;
2018 }
2019
Dmitry-Me72801b82015-05-07 09:41:39 +03002020 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002021 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002024
Dmitry-Me72801b82015-05-07 09:41:39 +03002025 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002026 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _charBuffer = new char[size+1];
2028 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 if ( read != size ) {
2030 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002033
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002035
Dmitry-Me97476b72015-01-01 16:15:57 +03002036 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002038}
2039
2040
Lee Thomason2fa81722012-11-09 12:37:46 -08002041XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002042{
Dmitry-Me01578db2014-08-19 10:18:48 +04002043 FILE* fp = callfopen( filename, "w" );
2044 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 }
2048 SaveFile(fp, compact);
2049 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002051}
2052
2053
Lee Thomason2fa81722012-11-09 12:37:46 -08002054XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002055{
Ant Mitchell189198f2015-03-24 16:20:36 +00002056 // Clear any error from the last save, otherwise it will get reported
2057 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002058 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 XMLPrinter stream( fp, compact );
2060 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002062}
2063
Lee Thomason1ff38e02012-02-14 18:18:16 -08002064
Lee Thomason2fa81722012-11-09 12:37:46 -08002065XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002066{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002067 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002068
Lee Thomason82d32002014-02-21 22:47:18 -08002069 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002071 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 }
2073 if ( len == (size_t)(-1) ) {
2074 len = strlen( p );
2075 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002076 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _charBuffer = new char[ len+1 ];
2078 memcpy( _charBuffer, p, len );
2079 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002080
Dmitry-Me97476b72015-01-01 16:15:57 +03002081 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002082 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002083 // clean up now essentially dangling memory.
2084 // and the parse fail can put objects in the
2085 // pools that are dead and inaccessible.
2086 DeleteChildren();
2087 _elementPool.Clear();
2088 _attributePool.Clear();
2089 _textPool.Clear();
2090 _commentPool.Clear();
2091 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002093}
2094
2095
PKEuS1c5f99e2013-07-06 11:28:39 +02002096void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002097{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002098 if ( streamer ) {
2099 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002101 else {
2102 XMLPrinter stdoutStreamer( stdout );
2103 Accept( &stdoutStreamer );
2104 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002105}
2106
2107
Lee Thomason2fa81722012-11-09 12:37:46 -08002108void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002109{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002110 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002111 _errorID = error;
2112 _errorStr1 = str1;
2113 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002114}
2115
Lee Thomason331596e2014-09-11 14:56:43 -07002116const char* XMLDocument::ErrorName() const
2117{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002118 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002119 const char* errorName = _errorNames[_errorID];
2120 TIXMLASSERT( errorName && errorName[0] );
2121 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002122}
Lee Thomason5cae8972012-01-24 18:03:07 -08002123
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002124void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002125{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002126 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 static const int LEN = 20;
2128 char buf1[LEN] = { 0 };
2129 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002130
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 if ( _errorStr1 ) {
2132 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _errorStr2 ) {
2135 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002137
Dmitry-Me2ad43202015-04-16 12:18:58 +03002138 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2139 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2140 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002141 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002142 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002144}
2145
Dmitry-Me97476b72015-01-01 16:15:57 +03002146void XMLDocument::Parse()
2147{
2148 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2149 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002150 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002151 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002152 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002153 if ( !*p ) {
2154 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2155 return;
2156 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002157 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002158}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002159
PKEuS1bfb9542013-08-04 13:51:17 +02002160XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 _elementJustOpened( false ),
2162 _firstElement( true ),
2163 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002164 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 _textDepth( -1 ),
2166 _processEntities( true ),
2167 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _entityFlag[i] = false;
2171 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 }
2173 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002174 const char entityValue = entities[i].value;
2175 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2176 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002178 _restrictedEntityFlag[(unsigned char)'&'] = true;
2179 _restrictedEntityFlag[(unsigned char)'<'] = true;
2180 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002182}
2183
2184
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002185void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002186{
2187 va_list va;
2188 va_start( va, format );
2189
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 if ( _fp ) {
2191 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 }
2193 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002194 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 // Close out and re-start the va-args
2196 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002197 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002199 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002200 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002201 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002203 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002204}
2205
2206
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002207void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 for( int i=0; i<depth; ++i ) {
2210 Print( " " );
2211 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002212}
2213
2214
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002215void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 // Look for runs of bytes between entities to print.
2218 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002219
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002221 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002223 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 // Remember, char is sometimes signed. (How many times has that bitten me?)
2225 if ( *q > 0 && *q < ENTITY_RANGE ) {
2226 // Check for entities. If one is found, flush
2227 // the stream up until the entity, write the
2228 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002229 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002231 const size_t delta = q - p;
2232 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002233 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002234 Print( "%.*s", toPrint, p );
2235 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002237 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 for( int i=0; i<NUM_ENTITIES; ++i ) {
2239 if ( entities[i].value == *q ) {
2240 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002241 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 break;
2243 }
2244 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002245 if ( !entityPatternPrinted ) {
2246 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2247 TIXMLASSERT( false );
2248 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 ++p;
2250 }
2251 }
2252 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002253 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 }
2255 }
2256 // Flush the remaining string. This will be the entire
2257 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002258 TIXMLASSERT( p <= q );
2259 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "%s", p );
2261 }
Lee Thomason857b8682012-01-25 17:50:25 -08002262}
2263
U-Stream\Leeae25a442012-02-17 17:48:16 -08002264
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002265void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002268 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 -07002269 Print( "%s", bom );
2270 }
2271 if ( writeDec ) {
2272 PushDeclaration( "xml version=\"1.0\"" );
2273 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002274}
2275
2276
Uli Kusterer593a33d2014-02-01 12:48:51 +01002277void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002278{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002279 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002280 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002281
Uli Kusterer593a33d2014-02-01 12:48:51 +01002282 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002284 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002285 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 _elementJustOpened = true;
2291 _firstElement = false;
2292 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002293}
2294
2295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002297{
Lee Thomason624d43f2012-10-12 10:58:48 -07002298 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 Print( " %s=\"", name );
2300 PrintString( value, false );
2301 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002302}
2303
2304
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002305void XMLPrinter::PushAttribute( const char* name, int v )
2306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 char buf[BUF_SIZE];
2308 XMLUtil::ToStr( v, buf, BUF_SIZE );
2309 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002310}
2311
2312
2313void XMLPrinter::PushAttribute( const char* name, unsigned v )
2314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 char buf[BUF_SIZE];
2316 XMLUtil::ToStr( v, buf, BUF_SIZE );
2317 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002318}
2319
2320
Lee Thomason51c12712016-06-04 20:18:49 -07002321void XMLPrinter::PushAttribute(const char* name, int64_t v)
2322{
2323 char buf[BUF_SIZE];
2324 XMLUtil::ToStr(v, buf, BUF_SIZE);
2325 PushAttribute(name, buf);
2326}
2327
2328
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002329void XMLPrinter::PushAttribute( const char* name, bool v )
2330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 char buf[BUF_SIZE];
2332 XMLUtil::ToStr( v, buf, BUF_SIZE );
2333 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002334}
2335
2336
2337void XMLPrinter::PushAttribute( const char* name, double v )
2338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 char buf[BUF_SIZE];
2340 XMLUtil::ToStr( v, buf, BUF_SIZE );
2341 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002342}
2343
2344
Uli Kustererca412e82014-02-01 13:35:05 +01002345void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002346{
Lee Thomason624d43f2012-10-12 10:58:48 -07002347 --_depth;
2348 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002349
Lee Thomason624d43f2012-10-12 10:58:48 -07002350 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 Print( "/>" );
2352 }
2353 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002354 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 }
2358 Print( "</%s>", name );
2359 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002360
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 if ( _textDepth == _depth ) {
2362 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 }
Uli Kustererca412e82014-02-01 13:35:05 +01002364 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 Print( "\n" );
2366 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002367 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002368}
2369
2370
Dmitry-Mea092bc12014-12-23 17:57:05 +03002371void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002372{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002373 if ( !_elementJustOpened ) {
2374 return;
2375 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002378}
2379
2380
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002381void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002382{
Lee Thomason624d43f2012-10-12 10:58:48 -07002383 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002384
Dmitry-Mea092bc12014-12-23 17:57:05 +03002385 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002387 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 }
2389 else {
2390 PrintString( text, true );
2391 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002392}
2393
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002394void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002395{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 char buf[BUF_SIZE];
2397 XMLUtil::ToStr( value, buf, BUF_SIZE );
2398 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002399}
2400
2401
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002402void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 char buf[BUF_SIZE];
2405 XMLUtil::ToStr( value, buf, BUF_SIZE );
2406 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002407}
2408
2409
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002410void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 char buf[BUF_SIZE];
2413 XMLUtil::ToStr( value, buf, BUF_SIZE );
2414 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002415}
2416
2417
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002418void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002420 char buf[BUF_SIZE];
2421 XMLUtil::ToStr( value, buf, BUF_SIZE );
2422 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002423}
2424
2425
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002426void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 char buf[BUF_SIZE];
2429 XMLUtil::ToStr( value, buf, BUF_SIZE );
2430 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002431}
2432
Lee Thomason5cae8972012-01-24 18:03:07 -08002433
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002434void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002435{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002436 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002437 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002439 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002443}
Lee Thomason751da522012-02-10 08:50:51 -08002444
2445
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002446void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002447{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002448 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002449 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002450 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002451 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002455}
2456
2457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002458void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002459{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002460 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002461 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002463 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002467}
2468
2469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002470bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002471{
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002473 if ( doc.HasBOM() ) {
2474 PushHeader( true, false );
2475 }
2476 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002477}
2478
2479
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002480bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002481{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002482 const XMLElement* parentElem = 0;
2483 if ( element.Parent() ) {
2484 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002485 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002486 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002487 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002488 while ( attribute ) {
2489 PushAttribute( attribute->Name(), attribute->Value() );
2490 attribute = attribute->Next();
2491 }
2492 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002493}
2494
2495
Uli Kustererca412e82014-02-01 13:35:05 +01002496bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002497{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002498 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002500}
2501
2502
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002503bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002504{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002505 PushText( text.Value(), text.CData() );
2506 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002507}
2508
2509
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002510bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002511{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002512 PushComment( comment.Value() );
2513 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002514}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002515
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002516bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 PushDeclaration( declaration.Value() );
2519 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002520}
2521
2522
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002523bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 PushUnknown( unknown.Value() );
2526 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002527}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002528
Lee Thomason685b8952012-11-12 13:00:06 -08002529} // namespace tinyxml2
2530