blob: 5f3ba8bfbb07c1490ffd4dd09f48461c0f35b09f [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
559bool XMLUtil::ToInt( const char* str, int* value )
560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
562 return true;
563 }
564 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700565}
566
567bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
570 return true;
571 }
572 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700573}
574
575bool XMLUtil::ToBool( const char* str, bool* value )
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 int ival = 0;
578 if ( ToInt( str, &ival )) {
579 *value = (ival==0) ? false : true;
580 return true;
581 }
582 if ( StringEqual( str, "true" ) ) {
583 *value = true;
584 return true;
585 }
586 else if ( StringEqual( str, "false" ) ) {
587 *value = false;
588 return true;
589 }
590 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700591}
592
593
594bool XMLUtil::ToFloat( const char* str, float* value )
595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
597 return true;
598 }
599 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700600}
601
602bool XMLUtil::ToDouble( const char* str, double* value )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
605 return true;
606 }
607 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700608}
609
610
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700611char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800612{
Dmitry-Me02384662015-03-03 16:02:13 +0300613 TIXMLASSERT( node );
614 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400615 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300617 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300618 *node = 0;
619 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 return p;
621 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622
Dmitry-Me962083b2015-05-26 11:38:30 +0300623 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 static const char* xmlHeader = { "<?" };
625 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300627 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800629
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 static const int xmlHeaderLen = 2;
631 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300633 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
637 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400638 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300640 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
642 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 p += xmlHeaderLen;
644 }
645 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300646 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 returnNode = new (_commentPool.Alloc()) XMLComment( this );
648 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 p += commentHeaderLen;
650 }
651 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300652 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 p += cdataHeaderLen;
657 text->SetCData( true );
658 }
659 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300660 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
662 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 p += dtdHeaderLen;
664 }
665 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300666 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 returnNode = new (_elementPool.Alloc()) XMLElement( this );
668 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 p += elementHeaderLen;
670 }
671 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300672 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 returnNode = new (_textPool.Alloc()) XMLText( this );
674 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 p = start; // Back it up, all the text counts.
676 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677
Dmitry-Me02384662015-03-03 16:02:13 +0300678 TIXMLASSERT( returnNode );
679 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 *node = returnNode;
681 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682}
683
684
Lee Thomason751da522012-02-10 08:50:51 -0800685bool XMLDocument::Accept( XMLVisitor* visitor ) const
686{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300687 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 if ( visitor->VisitEnter( *this ) ) {
689 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
690 if ( !node->Accept( visitor ) ) {
691 break;
692 }
693 }
694 }
695 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800696}
Lee Thomason56bdd022012-02-09 18:16:58 -0800697
698
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699// --------- XMLNode ----------- //
700
701XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 _document( doc ),
703 _parent( 0 ),
704 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200705 _prev( 0 ), _next( 0 ),
706 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800708}
709
710
711XMLNode::~XMLNode()
712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700713 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 if ( _parent ) {
715 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800717}
718
Michael Daumling21626882013-10-22 17:03:37 +0200719const char* XMLNode::Value() const
720{
Lee Thomason85492022015-05-22 11:07:45 -0700721 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530722 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530723 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200724 return _value.GetStr();
725}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800726
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800727void XMLNode::SetValue( const char* str, bool staticMem )
728{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
732 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800735}
736
737
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800738void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800739{
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300741 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300742 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700745
Dmitry-Mee3225b12014-09-03 11:03:11 +0400746 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800749}
750
751
752void XMLNode::Unlink( XMLNode* child )
753{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300754 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300755 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300756 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( child == _firstChild ) {
758 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 if ( child == _lastChild ) {
761 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomasond923c672012-01-23 08:44:25 -0800763
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 if ( child->_prev ) {
765 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 if ( child->_next ) {
768 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700770 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800771}
772
773
U-Stream\Leeae25a442012-02-17 17:48:16 -0800774void XMLNode::DeleteChild( XMLNode* node )
775{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300776 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300777 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100779 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400780 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800781}
782
783
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800784XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
785{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300786 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300787 if ( addThis->_document != _document ) {
788 TIXMLASSERT( false );
789 return 0;
790 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800791 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700792
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 if ( _lastChild ) {
794 TIXMLASSERT( _firstChild );
795 TIXMLASSERT( _lastChild->_next == 0 );
796 _lastChild->_next = addThis;
797 addThis->_prev = _lastChild;
798 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800799
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 }
802 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 TIXMLASSERT( _firstChild == 0 );
804 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 addThis->_prev = 0;
807 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800811}
812
813
Lee Thomason1ff38e02012-02-14 18:18:16 -0800814XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
815{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300816 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300817 if ( addThis->_document != _document ) {
818 TIXMLASSERT( false );
819 return 0;
820 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800821 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 if ( _firstChild ) {
824 TIXMLASSERT( _lastChild );
825 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 _firstChild->_prev = addThis;
828 addThis->_next = _firstChild;
829 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
833 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 TIXMLASSERT( _lastChild == 0 );
835 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800836
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 addThis->_prev = 0;
838 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400841 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800842}
843
844
845XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
846{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300847 TIXMLASSERT( addThis );
848 if ( addThis->_document != _document ) {
849 TIXMLASSERT( false );
850 return 0;
851 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700852
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700854
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300856 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 return 0;
858 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 // The last node or the only node.
862 return InsertEndChild( addThis );
863 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800864 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_prev = afterThis;
866 addThis->_next = afterThis->_next;
867 afterThis->_next->_prev = addThis;
868 afterThis->_next = addThis;
869 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800871}
872
873
874
875
Dmitry-Me886ad972015-07-22 11:00:51 +0300876const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800877{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300878 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
879 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300881 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 return element;
883 }
884 }
885 }
886 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800887}
888
889
Dmitry-Me886ad972015-07-22 11:00:51 +0300890const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800891{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300892 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
893 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300895 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 return element;
897 }
898 }
899 }
900 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800901}
902
903
Dmitry-Me886ad972015-07-22 11:00:51 +0300904const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300906 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400907 const XMLElement* element = node->ToElement();
908 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300909 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400910 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 }
913 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800914}
915
916
Dmitry-Me886ad972015-07-22 11:00:51 +0300917const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800918{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300919 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400920 const XMLElement* element = node->ToElement();
921 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300922 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400923 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
925 }
926 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800927}
928
929
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800930char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800931{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 // This is a recursive method, but thinking about it "at the current level"
933 // it is a pretty simple flat list:
934 // <foo/>
935 // <!-- comment -->
936 //
937 // With a special case:
938 // <foo>
939 // </foo>
940 // <!-- comment -->
941 //
942 // Where the closing element (/foo) *must* be the next thing after the opening
943 // element, and the names must match. BUT the tricky bit is that the closing
944 // element will be read by the child.
945 //
946 // 'endTag' is the end tag for this node, it is returned by a call to a child.
947 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800948
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 while( p && *p ) {
950 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800951
Lee Thomason624d43f2012-10-12 10:58:48 -0700952 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300953 if ( node == 0 ) {
954 break;
955 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800956
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 StrPair endTag;
958 p = node->ParseDeep( p, &endTag );
959 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400960 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700961 if ( !_document->Error() ) {
962 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 }
964 break;
965 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530967 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530968 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530969 // A declaration can only be the first child of a document.
970 // Set error, if document already has children.
971 if ( !_document->NoChildren() ) {
972 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
973 DeleteNode( decl );
974 break;
975 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530976 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530977
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400978 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500980 // We read the end tag. Return it to the parent.
981 if ( ele->ClosingType() == XMLElement::CLOSING ) {
982 if ( parentEnd ) {
983 ele->_value.TransferTo( parentEnd );
984 }
985 node->_memPool->SetTracked(); // created and then immediately deleted.
986 DeleteNode( node );
987 return p;
988 }
989
990 // Handle an end tag returned to this level.
991 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400992 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300993 if ( endTag.Empty() ) {
994 if ( ele->ClosingType() == XMLElement::OPEN ) {
995 mismatch = true;
996 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300998 else {
999 if ( ele->ClosingType() != XMLElement::OPEN ) {
1000 mismatch = true;
1001 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001002 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001003 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001006 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001007 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001008 DeleteNode( node );
1009 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001010 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
JayXondbfdd8f2014-12-12 20:07:14 -05001012 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 }
1014 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001015}
1016
Dmitry-Mee3225b12014-09-03 11:03:11 +04001017void XMLNode::DeleteNode( XMLNode* node )
1018{
1019 if ( node == 0 ) {
1020 return;
1021 }
1022 MemPool* pool = node->_memPool;
1023 node->~XMLNode();
1024 pool->Free( node );
1025}
1026
Lee Thomason3cebdc42015-01-05 17:16:28 -08001027void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001028{
1029 TIXMLASSERT( insertThis );
1030 TIXMLASSERT( insertThis->_document == _document );
1031
1032 if ( insertThis->_parent )
1033 insertThis->_parent->Unlink( insertThis );
1034 else
1035 insertThis->_memPool->SetTracked();
1036}
1037
Lee Thomason5492a1c2012-01-23 15:32:10 -08001038// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001039char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 const char* start = p;
1042 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 }
1047 return p;
1048 }
1049 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1051 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001052 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001054
Lee Thomason624d43f2012-10-12 10:58:48 -07001055 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 if ( p && *p ) {
1057 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001058 }
1059 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001060 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 }
1062 }
1063 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001064}
1065
1066
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001067XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 }
1072 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1073 text->SetCData( this->CData() );
1074 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001075}
1076
1077
1078bool XMLText::ShallowEqual( const XMLNode* compare ) const
1079{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001080 const XMLText* text = compare->ToText();
1081 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001082}
1083
1084
Lee Thomason56bdd022012-02-09 18:16:58 -08001085bool XMLText::Accept( XMLVisitor* visitor ) const
1086{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001087 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001089}
1090
1091
Lee Thomason3f57d272012-01-11 15:30:03 -08001092// --------- XMLComment ---------- //
1093
Lee Thomasone4422302012-01-20 17:59:50 -08001094XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001095{
1096}
1097
1098
Lee Thomasonce0763e2012-01-11 15:43:54 -08001099XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001100{
Lee Thomason3f57d272012-01-11 15:30:03 -08001101}
1102
1103
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001104char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001105{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 // Comment parses as text.
1107 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001110 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001113}
1114
1115
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001116XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001119 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1122 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123}
1124
1125
1126bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1127{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001128 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001129 const XMLComment* comment = compare->ToComment();
1130 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
Lee Thomason751da522012-02-10 08:50:51 -08001134bool XMLComment::Accept( XMLVisitor* visitor ) const
1135{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001136 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001138}
Lee Thomason56bdd022012-02-09 18:16:58 -08001139
1140
Lee Thomason50f97b22012-02-11 16:33:40 -08001141// --------- XMLDeclaration ---------- //
1142
1143XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1144{
1145}
1146
1147
1148XMLDeclaration::~XMLDeclaration()
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001151}
1152
1153
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001154char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 // Declaration parses as text.
1157 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 }
1162 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001163}
1164
1165
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001166XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001169 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 }
1171 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1172 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001173}
1174
1175
1176bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1177{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001178 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001179 const XMLDeclaration* declaration = compare->ToDeclaration();
1180 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001181}
1182
1183
1184
Lee Thomason50f97b22012-02-11 16:33:40 -08001185bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1186{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001187 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001189}
1190
1191// --------- XMLUnknown ---------- //
1192
1193XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1194{
1195}
1196
1197
1198XMLUnknown::~XMLUnknown()
1199{
1200}
1201
1202
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001203char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 // Unknown parses as text.
1206 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001207
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 }
1212 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001213}
1214
1215
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001216XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001219 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 }
1221 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1222 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001223}
1224
1225
1226bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1227{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001228 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001229 const XMLUnknown* unknown = compare->ToUnknown();
1230 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001231}
1232
1233
Lee Thomason50f97b22012-02-11 16:33:40 -08001234bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1235{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001236 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001238}
1239
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001240// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001241
1242const char* XMLAttribute::Name() const
1243{
1244 return _name.GetStr();
1245}
1246
1247const char* XMLAttribute::Value() const
1248{
1249 return _value.GetStr();
1250}
1251
Lee Thomason6f381b72012-03-02 12:59:39 -08001252char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001253{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( !p || !*p ) {
1257 return 0;
1258 }
Lee Thomason22aead12012-01-23 13:29:35 -08001259
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 // Skip white space before =
1261 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001262 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 return 0;
1264 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001265
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 ++p; // move up to opening quote
1267 p = XMLUtil::SkipWhiteSpace( p );
1268 if ( *p != '\"' && *p != '\'' ) {
1269 return 0;
1270 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001271
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 char endTag[2] = { *p, 0 };
1273 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001274
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001277}
1278
1279
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001280void XMLAttribute::SetName( const char* n )
1281{
Lee Thomason624d43f2012-10-12 10:58:48 -07001282 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001283}
1284
1285
Lee Thomason2fa81722012-11-09 12:37:46 -08001286XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001289 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 }
1291 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001292}
1293
1294
Lee Thomason2fa81722012-11-09 12:37:46 -08001295XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001298 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 }
1300 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001301}
1302
1303
Lee Thomason2fa81722012-11-09 12:37:46 -08001304XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001307 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 }
1309 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001310}
1311
1312
Lee Thomason2fa81722012-11-09 12:37:46 -08001313XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001316 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 }
1318 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001319}
1320
1321
Lee Thomason2fa81722012-11-09 12:37:46 -08001322XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001325 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 }
1327 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001328}
1329
1330
1331void XMLAttribute::SetAttribute( const char* v )
1332{
Lee Thomason624d43f2012-10-12 10:58:48 -07001333 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001334}
1335
1336
Lee Thomason1ff38e02012-02-14 18:18:16 -08001337void XMLAttribute::SetAttribute( int v )
1338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001341 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001343
1344
1345void XMLAttribute::SetAttribute( unsigned v )
1346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001350}
1351
1352
1353void XMLAttribute::SetAttribute( bool v )
1354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 char buf[BUF_SIZE];
1356 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001357 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001358}
1359
1360void XMLAttribute::SetAttribute( double v )
1361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 char buf[BUF_SIZE];
1363 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001364 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001365}
1366
1367void XMLAttribute::SetAttribute( float v )
1368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001372}
1373
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001374
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001375// --------- XMLElement ---------- //
1376XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _closingType( 0 ),
1378 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001379{
1380}
1381
1382
1383XMLElement::~XMLElement()
1384{
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 while( _rootAttribute ) {
1386 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001387 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001390}
1391
1392
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1394{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001395 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1397 return a;
1398 }
1399 }
1400 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001401}
1402
1403
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001404const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 const XMLAttribute* a = FindAttribute( name );
1407 if ( !a ) {
1408 return 0;
1409 }
1410 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1411 return a->Value();
1412 }
1413 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001414}
1415
1416
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001417const char* XMLElement::GetText() const
1418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001420 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
1422 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001423}
1424
1425
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001426void XMLElement::SetText( const char* inText )
1427{
Uli Kusterer869bb592014-01-21 01:36:16 +01001428 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001429 FirstChild()->SetValue( inText );
1430 else {
1431 XMLText* theText = GetDocument()->NewText( inText );
1432 InsertFirstChild( theText );
1433 }
1434}
1435
Lee Thomason5bb2d802014-01-24 10:42:57 -08001436
1437void XMLElement::SetText( int v )
1438{
1439 char buf[BUF_SIZE];
1440 XMLUtil::ToStr( v, buf, BUF_SIZE );
1441 SetText( buf );
1442}
1443
1444
1445void XMLElement::SetText( unsigned v )
1446{
1447 char buf[BUF_SIZE];
1448 XMLUtil::ToStr( v, buf, BUF_SIZE );
1449 SetText( buf );
1450}
1451
1452
1453void XMLElement::SetText( bool v )
1454{
1455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
1457 SetText( buf );
1458}
1459
1460
1461void XMLElement::SetText( float v )
1462{
1463 char buf[BUF_SIZE];
1464 XMLUtil::ToStr( v, buf, BUF_SIZE );
1465 SetText( buf );
1466}
1467
1468
1469void XMLElement::SetText( double v )
1470{
1471 char buf[BUF_SIZE];
1472 XMLUtil::ToStr( v, buf, BUF_SIZE );
1473 SetText( buf );
1474}
1475
1476
MortenMacFly4ee49f12013-01-14 20:03:14 +01001477XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001480 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001481 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 return XML_SUCCESS;
1483 }
1484 return XML_CAN_NOT_CONVERT_TEXT;
1485 }
1486 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001487}
1488
1489
MortenMacFly4ee49f12013-01-14 20:03:14 +01001490XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001493 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001494 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 return XML_SUCCESS;
1496 }
1497 return XML_CAN_NOT_CONVERT_TEXT;
1498 }
1499 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001500}
1501
1502
MortenMacFly4ee49f12013-01-14 20:03:14 +01001503XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001504{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001506 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001507 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 return XML_SUCCESS;
1509 }
1510 return XML_CAN_NOT_CONVERT_TEXT;
1511 }
1512 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001513}
1514
1515
MortenMacFly4ee49f12013-01-14 20:03:14 +01001516XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001519 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001520 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return XML_SUCCESS;
1522 }
1523 return XML_CAN_NOT_CONVERT_TEXT;
1524 }
1525 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001526}
1527
1528
MortenMacFly4ee49f12013-01-14 20:03:14 +01001529XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001532 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001533 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 return XML_SUCCESS;
1535 }
1536 return XML_CAN_NOT_CONVERT_TEXT;
1537 }
1538 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001539}
1540
1541
1542
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001543XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 XMLAttribute* last = 0;
1546 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1551 break;
1552 }
1553 }
1554 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001555 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1557 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 }
1561 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001562 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 }
1564 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001565 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 }
1567 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001568}
1569
1570
U-Stream\Leeae25a442012-02-17 17:48:16 -08001571void XMLElement::DeleteAttribute( const char* name )
1572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1576 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 }
1579 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001580 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001582 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 break;
1584 }
1585 prev = a;
1586 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001587}
1588
1589
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001590char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 const char* start = p;
1593 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001594
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 // Read the attributes.
1596 while( p ) {
1597 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001598 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001599 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 return 0;
1601 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001602
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001604 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001605 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1607 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001608 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001609
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001612 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 return 0;
1615 }
1616 // There is a minor bug here: if the attribute in the source xml
1617 // document is duplicated, it will not be detected and the
1618 // attribute will be doubly added. However, tracking the 'prevAttribute'
1619 // avoids re-scanning the attribute list. Preferring performance for
1620 // now, may reconsider in the future.
1621 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 }
1624 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 }
1627 prevAttribute = attrib;
1628 }
1629 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 else if ( *p == '>' ) {
1631 ++p;
1632 break;
1633 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001634 // end of the tag
1635 else if ( *p == '/' && *(p+1) == '>' ) {
1636 _closingType = CLOSED;
1637 return p+2; // done; sealed element.
1638 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 return 0;
1642 }
1643 }
1644 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001645}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001646
Dmitry-Mee3225b12014-09-03 11:03:11 +04001647void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1648{
1649 if ( attribute == 0 ) {
1650 return;
1651 }
1652 MemPool* pool = attribute->_memPool;
1653 attribute->~XMLAttribute();
1654 pool->Free( attribute );
1655}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001656
Lee Thomason67d61312012-01-24 16:01:51 -08001657//
1658// <ele></ele>
1659// <ele>foo<b>bar</b></ele>
1660//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001661char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001662{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 // Read the element name.
1664 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001665
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 // The closing element is the </element> form. It is
1667 // parsed just like a regular element then deleted from
1668 // the DOM.
1669 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 ++p;
1672 }
Lee Thomason67d61312012-01-24 16:01:51 -08001673
Lee Thomason624d43f2012-10-12 10:58:48 -07001674 p = _value.ParseName( p );
1675 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 return 0;
1677 }
Lee Thomason67d61312012-01-24 16:01:51 -08001678
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 return p;
1682 }
Lee Thomason67d61312012-01-24 16:01:51 -08001683
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 p = XMLNode::ParseDeep( p, strPair );
1685 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001686}
1687
1688
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001689
1690XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 }
1695 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1696 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1697 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1698 }
1699 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001700}
1701
1702
1703bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1704{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001705 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001707 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001708
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 const XMLAttribute* a=FirstAttribute();
1710 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001711
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 while ( a && b ) {
1713 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1714 return false;
1715 }
1716 a = a->Next();
1717 b = b->Next();
1718 }
1719 if ( a || b ) {
1720 // different count
1721 return false;
1722 }
1723 return true;
1724 }
1725 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001726}
1727
1728
Lee Thomason751da522012-02-10 08:50:51 -08001729bool XMLElement::Accept( XMLVisitor* visitor ) const
1730{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001731 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1734 if ( !node->Accept( visitor ) ) {
1735 break;
1736 }
1737 }
1738 }
1739 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001740}
Lee Thomason56bdd022012-02-09 18:16:58 -08001741
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001742
Lee Thomason3f57d272012-01-11 15:30:03 -08001743// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001744
1745// Warning: List must match 'enum XMLError'
1746const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1747 "XML_SUCCESS",
1748 "XML_NO_ATTRIBUTE",
1749 "XML_WRONG_ATTRIBUTE_TYPE",
1750 "XML_ERROR_FILE_NOT_FOUND",
1751 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1752 "XML_ERROR_FILE_READ_ERROR",
1753 "XML_ERROR_ELEMENT_MISMATCH",
1754 "XML_ERROR_PARSING_ELEMENT",
1755 "XML_ERROR_PARSING_ATTRIBUTE",
1756 "XML_ERROR_IDENTIFYING_TAG",
1757 "XML_ERROR_PARSING_TEXT",
1758 "XML_ERROR_PARSING_CDATA",
1759 "XML_ERROR_PARSING_COMMENT",
1760 "XML_ERROR_PARSING_DECLARATION",
1761 "XML_ERROR_PARSING_UNKNOWN",
1762 "XML_ERROR_EMPTY_DOCUMENT",
1763 "XML_ERROR_MISMATCHED_ELEMENT",
1764 "XML_ERROR_PARSING",
1765 "XML_CAN_NOT_CONVERT_TEXT",
1766 "XML_NO_TEXT_NODE"
1767};
1768
1769
Lee Thomason624d43f2012-10-12 10:58:48 -07001770XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 _writeBOM( false ),
1773 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001774 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 _whitespace( whitespace ),
1776 _errorStr1( 0 ),
1777 _errorStr2( 0 ),
1778 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001779{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001780 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1781 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001782}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001783
1784
Lee Thomason3f57d272012-01-11 15:30:03 -08001785XMLDocument::~XMLDocument()
1786{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001787 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001788}
1789
1790
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001791void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001792{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001793 DeleteChildren();
1794
Dmitry-Meab37df82014-11-28 12:08:36 +03001795#ifdef DEBUG
1796 const bool hadError = Error();
1797#endif
Lee Thomason85536252016-06-04 19:10:53 -07001798 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 _errorStr1 = 0;
1800 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001801
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 delete [] _charBuffer;
1803 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001804
1805#if 0
1806 _textPool.Trace( "text" );
1807 _elementPool.Trace( "element" );
1808 _commentPool.Trace( "comment" );
1809 _attributePool.Trace( "attribute" );
1810#endif
1811
1812#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001813 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001814 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1815 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1816 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1817 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1818 }
1819#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001820}
1821
Lee Thomason3f57d272012-01-11 15:30:03 -08001822
Lee Thomason2c85a712012-01-31 08:24:24 -08001823XMLElement* XMLDocument::NewElement( const char* name )
1824{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001825 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1827 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 ele->SetName( name );
1829 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001830}
1831
1832
Lee Thomason1ff38e02012-02-14 18:18:16 -08001833XMLComment* XMLDocument::NewComment( const char* str )
1834{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001835 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1837 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 comment->SetValue( str );
1839 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001840}
1841
1842
1843XMLText* XMLDocument::NewText( const char* str )
1844{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001845 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1847 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 text->SetValue( str );
1849 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001850}
1851
1852
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001853XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1854{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001855 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1857 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1859 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001860}
1861
1862
1863XMLUnknown* XMLDocument::NewUnknown( const char* str )
1864{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001865 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1867 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 unk->SetValue( str );
1869 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001870}
1871
Dmitry-Me01578db2014-08-19 10:18:48 +04001872static FILE* callfopen( const char* filepath, const char* mode )
1873{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001874 TIXMLASSERT( filepath );
1875 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001876#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1877 FILE* fp = 0;
1878 errno_t err = fopen_s( &fp, filepath, mode );
1879 if ( err ) {
1880 return 0;
1881 }
1882#else
1883 FILE* fp = fopen( filepath, mode );
1884#endif
1885 return fp;
1886}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001887
1888void XMLDocument::DeleteNode( XMLNode* node ) {
1889 TIXMLASSERT( node );
1890 TIXMLASSERT(node->_document == this );
1891 if (node->_parent) {
1892 node->_parent->DeleteChild( node );
1893 }
1894 else {
1895 // Isn't in the tree.
1896 // Use the parent delete.
1897 // Also, we need to mark it tracked: we 'know'
1898 // it was never used.
1899 node->_memPool->SetTracked();
1900 // Call the static XMLNode version:
1901 XMLNode::DeleteNode(node);
1902 }
1903}
1904
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001905
Lee Thomason2fa81722012-11-09 12:37:46 -08001906XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001907{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001908 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001909 FILE* fp = callfopen( filename, "rb" );
1910 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 }
1914 LoadFile( fp );
1915 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001917}
1918
Dmitry-Me901fed52015-09-25 10:29:51 +03001919// This is likely overengineered template art to have a check that unsigned long value incremented
1920// by one still fits into size_t. If size_t type is larger than unsigned long type
1921// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1922// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1923// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1924// types sizes relate to each other.
1925template
1926<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1927struct LongFitsIntoSizeTMinusOne {
1928 static bool Fits( unsigned long value )
1929 {
1930 return value < (size_t)-1;
1931 }
1932};
1933
1934template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001935struct LongFitsIntoSizeTMinusOne<false> {
1936 static bool Fits( unsigned long )
1937 {
1938 return true;
1939 }
1940};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941
Lee Thomason2fa81722012-11-09 12:37:46 -08001942XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001944 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001945
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001946 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001947 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001948 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1949 return _errorID;
1950 }
1951
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001953 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001955 if ( filelength == -1L ) {
1956 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1957 return _errorID;
1958 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03001959 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001960
Dmitry-Me901fed52015-09-25 10:29:51 +03001961 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001962 // Cannot handle files which won't fit in buffer together with null terminator
1963 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1964 return _errorID;
1965 }
1966
Dmitry-Me72801b82015-05-07 09:41:39 +03001967 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001968 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001971
Dmitry-Me72801b82015-05-07 09:41:39 +03001972 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03001973 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 _charBuffer = new char[size+1];
1975 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 if ( read != size ) {
1977 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001980
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001982
Dmitry-Me97476b72015-01-01 16:15:57 +03001983 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001985}
1986
1987
Lee Thomason2fa81722012-11-09 12:37:46 -08001988XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001989{
Dmitry-Me01578db2014-08-19 10:18:48 +04001990 FILE* fp = callfopen( filename, "w" );
1991 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 }
1995 SaveFile(fp, compact);
1996 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001998}
1999
2000
Lee Thomason2fa81722012-11-09 12:37:46 -08002001XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002002{
Ant Mitchell189198f2015-03-24 16:20:36 +00002003 // Clear any error from the last save, otherwise it will get reported
2004 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002005 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 XMLPrinter stream( fp, compact );
2007 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002009}
2010
Lee Thomason1ff38e02012-02-14 18:18:16 -08002011
Lee Thomason2fa81722012-11-09 12:37:46 -08002012XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002013{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002014 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002015
Lee Thomason82d32002014-02-21 22:47:18 -08002016 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 }
2020 if ( len == (size_t)(-1) ) {
2021 len = strlen( p );
2022 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002023 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 _charBuffer = new char[ len+1 ];
2025 memcpy( _charBuffer, p, len );
2026 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002027
Dmitry-Me97476b72015-01-01 16:15:57 +03002028 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002029 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002030 // clean up now essentially dangling memory.
2031 // and the parse fail can put objects in the
2032 // pools that are dead and inaccessible.
2033 DeleteChildren();
2034 _elementPool.Clear();
2035 _attributePool.Clear();
2036 _textPool.Clear();
2037 _commentPool.Clear();
2038 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002040}
2041
2042
PKEuS1c5f99e2013-07-06 11:28:39 +02002043void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002044{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002045 if ( streamer ) {
2046 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002048 else {
2049 XMLPrinter stdoutStreamer( stdout );
2050 Accept( &stdoutStreamer );
2051 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002052}
2053
2054
Lee Thomason2fa81722012-11-09 12:37:46 -08002055void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002056{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002057 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 _errorID = error;
2059 _errorStr1 = str1;
2060 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002061}
2062
Lee Thomason331596e2014-09-11 14:56:43 -07002063const char* XMLDocument::ErrorName() const
2064{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002065 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002066 const char* errorName = _errorNames[_errorID];
2067 TIXMLASSERT( errorName && errorName[0] );
2068 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002069}
Lee Thomason5cae8972012-01-24 18:03:07 -08002070
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002071void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002072{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002073 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 static const int LEN = 20;
2075 char buf1[LEN] = { 0 };
2076 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002077
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 if ( _errorStr1 ) {
2079 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 if ( _errorStr2 ) {
2082 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002084
Dmitry-Me2ad43202015-04-16 12:18:58 +03002085 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2086 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2087 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002088 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002089 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002091}
2092
Dmitry-Me97476b72015-01-01 16:15:57 +03002093void XMLDocument::Parse()
2094{
2095 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2096 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002097 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002098 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002099 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002100 if ( !*p ) {
2101 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2102 return;
2103 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002104 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002105}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002106
PKEuS1bfb9542013-08-04 13:51:17 +02002107XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002108 _elementJustOpened( false ),
2109 _firstElement( true ),
2110 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002111 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 _textDepth( -1 ),
2113 _processEntities( true ),
2114 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 _entityFlag[i] = false;
2118 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 }
2120 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002121 const char entityValue = entities[i].value;
2122 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2123 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002125 _restrictedEntityFlag[(unsigned char)'&'] = true;
2126 _restrictedEntityFlag[(unsigned char)'<'] = true;
2127 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002129}
2130
2131
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002132void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002133{
2134 va_list va;
2135 va_start( va, format );
2136
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _fp ) {
2138 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 }
2140 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002141 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 // Close out and re-start the va-args
2143 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002144 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002146 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002147 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002148 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002150 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002151}
2152
2153
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002154void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 for( int i=0; i<depth; ++i ) {
2157 Print( " " );
2158 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002159}
2160
2161
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002162void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 // Look for runs of bytes between entities to print.
2165 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002166
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002168 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002170 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 // Remember, char is sometimes signed. (How many times has that bitten me?)
2172 if ( *q > 0 && *q < ENTITY_RANGE ) {
2173 // Check for entities. If one is found, flush
2174 // the stream up until the entity, write the
2175 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002176 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002178 const size_t delta = q - p;
2179 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002180 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002181 Print( "%.*s", toPrint, p );
2182 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002184 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 for( int i=0; i<NUM_ENTITIES; ++i ) {
2186 if ( entities[i].value == *q ) {
2187 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002188 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 break;
2190 }
2191 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002192 if ( !entityPatternPrinted ) {
2193 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2194 TIXMLASSERT( false );
2195 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 ++p;
2197 }
2198 }
2199 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002200 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 }
2202 }
2203 // Flush the remaining string. This will be the entire
2204 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002205 TIXMLASSERT( p <= q );
2206 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 Print( "%s", p );
2208 }
Lee Thomason857b8682012-01-25 17:50:25 -08002209}
2210
U-Stream\Leeae25a442012-02-17 17:48:16 -08002211
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002212void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002215 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 -07002216 Print( "%s", bom );
2217 }
2218 if ( writeDec ) {
2219 PushDeclaration( "xml version=\"1.0\"" );
2220 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002221}
2222
2223
Uli Kusterer593a33d2014-02-01 12:48:51 +01002224void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002225{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002226 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002228
Uli Kusterer593a33d2014-02-01 12:48:51 +01002229 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002231 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002232 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002235
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 _elementJustOpened = true;
2238 _firstElement = false;
2239 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002240}
2241
2242
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002243void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002244{
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 Print( " %s=\"", name );
2247 PrintString( value, false );
2248 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002249}
2250
2251
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002252void XMLPrinter::PushAttribute( const char* name, int v )
2253{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 char buf[BUF_SIZE];
2255 XMLUtil::ToStr( v, buf, BUF_SIZE );
2256 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002257}
2258
2259
2260void XMLPrinter::PushAttribute( const char* name, unsigned v )
2261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 char buf[BUF_SIZE];
2263 XMLUtil::ToStr( v, buf, BUF_SIZE );
2264 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002265}
2266
2267
2268void XMLPrinter::PushAttribute( const char* name, bool v )
2269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 char buf[BUF_SIZE];
2271 XMLUtil::ToStr( v, buf, BUF_SIZE );
2272 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002273}
2274
2275
2276void XMLPrinter::PushAttribute( const char* name, double v )
2277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 char buf[BUF_SIZE];
2279 XMLUtil::ToStr( v, buf, BUF_SIZE );
2280 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002281}
2282
2283
Uli Kustererca412e82014-02-01 13:35:05 +01002284void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002285{
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 --_depth;
2287 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002288
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "/>" );
2291 }
2292 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002293 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 }
2297 Print( "</%s>", name );
2298 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002299
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 if ( _textDepth == _depth ) {
2301 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 }
Uli Kustererca412e82014-02-01 13:35:05 +01002303 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 Print( "\n" );
2305 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002306 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002307}
2308
2309
Dmitry-Mea092bc12014-12-23 17:57:05 +03002310void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002311{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002312 if ( !_elementJustOpened ) {
2313 return;
2314 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002315 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002317}
2318
2319
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002320void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002321{
Lee Thomason624d43f2012-10-12 10:58:48 -07002322 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002323
Dmitry-Mea092bc12014-12-23 17:57:05 +03002324 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002326 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 }
2328 else {
2329 PrintString( text, true );
2330 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002331}
2332
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002333void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 char buf[BUF_SIZE];
2336 XMLUtil::ToStr( value, buf, BUF_SIZE );
2337 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002338}
2339
2340
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002341void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002343 char buf[BUF_SIZE];
2344 XMLUtil::ToStr( value, buf, BUF_SIZE );
2345 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002346}
2347
2348
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002349void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002350{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 char buf[BUF_SIZE];
2352 XMLUtil::ToStr( value, buf, BUF_SIZE );
2353 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002354}
2355
2356
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002357void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 char buf[BUF_SIZE];
2360 XMLUtil::ToStr( value, buf, BUF_SIZE );
2361 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002362}
2363
2364
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002365void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 char buf[BUF_SIZE];
2368 XMLUtil::ToStr( value, buf, BUF_SIZE );
2369 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002370}
2371
Lee Thomason5cae8972012-01-24 18:03:07 -08002372
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002373void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002374{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002375 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002381 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002382}
Lee Thomason751da522012-02-10 08:50:51 -08002383
2384
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002385void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002386{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002387 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002390 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002391 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002392 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002394}
2395
2396
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002397void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002398{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002399 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002400 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002401 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002402 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002404 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002405 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002406}
2407
2408
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002409bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002410{
Lee Thomason624d43f2012-10-12 10:58:48 -07002411 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 if ( doc.HasBOM() ) {
2413 PushHeader( true, false );
2414 }
2415 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002416}
2417
2418
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002419bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002420{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002421 const XMLElement* parentElem = 0;
2422 if ( element.Parent() ) {
2423 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002424 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002425 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002426 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 while ( attribute ) {
2428 PushAttribute( attribute->Name(), attribute->Value() );
2429 attribute = attribute->Next();
2430 }
2431 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002432}
2433
2434
Uli Kustererca412e82014-02-01 13:35:05 +01002435bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002436{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002437 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002439}
2440
2441
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002442bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002444 PushText( text.Value(), text.CData() );
2445 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002446}
2447
2448
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002449bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 PushComment( comment.Value() );
2452 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002453}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002454
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002455bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 PushDeclaration( declaration.Value() );
2458 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002459}
2460
2461
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002462bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002463{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 PushUnknown( unknown.Value() );
2465 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002466}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002467
Lee Thomason685b8952012-11-12 13:00:06 -08002468} // namespace tinyxml2
2469