blob: bfd8d1f9eb81f4083cd2d4ac112f24908a49543a [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 <>
1935bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1936{
1937 return true;
1938}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001939
Lee Thomason2fa81722012-11-09 12:37:46 -08001940XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001942 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001944 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001945 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001946 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1947 return _errorID;
1948 }
1949
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001951 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001953 if ( filelength == -1L ) {
1954 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1955 return _errorID;
1956 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03001957 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001958
Dmitry-Me901fed52015-09-25 10:29:51 +03001959 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001960 // Cannot handle files which won't fit in buffer together with null terminator
1961 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1962 return _errorID;
1963 }
1964
Dmitry-Me72801b82015-05-07 09:41:39 +03001965 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001966 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001969
Dmitry-Me72801b82015-05-07 09:41:39 +03001970 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03001971 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 _charBuffer = new char[size+1];
1973 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 if ( read != size ) {
1975 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001978
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001980
Dmitry-Me97476b72015-01-01 16:15:57 +03001981 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001982 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001983}
1984
1985
Lee Thomason2fa81722012-11-09 12:37:46 -08001986XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001987{
Dmitry-Me01578db2014-08-19 10:18:48 +04001988 FILE* fp = callfopen( filename, "w" );
1989 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 }
1993 SaveFile(fp, compact);
1994 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001996}
1997
1998
Lee Thomason2fa81722012-11-09 12:37:46 -08001999XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002000{
Ant Mitchell189198f2015-03-24 16:20:36 +00002001 // Clear any error from the last save, otherwise it will get reported
2002 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002003 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 XMLPrinter stream( fp, compact );
2005 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002007}
2008
Lee Thomason1ff38e02012-02-14 18:18:16 -08002009
Lee Thomason2fa81722012-11-09 12:37:46 -08002010XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002011{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002012 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002013
Lee Thomason82d32002014-02-21 22:47:18 -08002014 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002016 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 }
2018 if ( len == (size_t)(-1) ) {
2019 len = strlen( p );
2020 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002021 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 _charBuffer = new char[ len+1 ];
2023 memcpy( _charBuffer, p, len );
2024 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002025
Dmitry-Me97476b72015-01-01 16:15:57 +03002026 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002027 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002028 // clean up now essentially dangling memory.
2029 // and the parse fail can put objects in the
2030 // pools that are dead and inaccessible.
2031 DeleteChildren();
2032 _elementPool.Clear();
2033 _attributePool.Clear();
2034 _textPool.Clear();
2035 _commentPool.Clear();
2036 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002038}
2039
2040
PKEuS1c5f99e2013-07-06 11:28:39 +02002041void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002042{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002043 if ( streamer ) {
2044 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002046 else {
2047 XMLPrinter stdoutStreamer( stdout );
2048 Accept( &stdoutStreamer );
2049 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002050}
2051
2052
Lee Thomason2fa81722012-11-09 12:37:46 -08002053void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002054{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002055 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 _errorID = error;
2057 _errorStr1 = str1;
2058 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002059}
2060
Lee Thomason331596e2014-09-11 14:56:43 -07002061const char* XMLDocument::ErrorName() const
2062{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002063 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002064 const char* errorName = _errorNames[_errorID];
2065 TIXMLASSERT( errorName && errorName[0] );
2066 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002067}
Lee Thomason5cae8972012-01-24 18:03:07 -08002068
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002069void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002070{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002071 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 static const int LEN = 20;
2073 char buf1[LEN] = { 0 };
2074 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002075
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 if ( _errorStr1 ) {
2077 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 if ( _errorStr2 ) {
2080 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002082
Dmitry-Me2ad43202015-04-16 12:18:58 +03002083 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2084 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2085 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002086 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002087 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002089}
2090
Dmitry-Me97476b72015-01-01 16:15:57 +03002091void XMLDocument::Parse()
2092{
2093 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2094 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002095 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002096 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002097 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002098 if ( !*p ) {
2099 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2100 return;
2101 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002102 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002103}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002104
PKEuS1bfb9542013-08-04 13:51:17 +02002105XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002106 _elementJustOpened( false ),
2107 _firstElement( true ),
2108 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002109 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 _textDepth( -1 ),
2111 _processEntities( true ),
2112 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002115 _entityFlag[i] = false;
2116 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 }
2118 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002119 const char entityValue = entities[i].value;
2120 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2121 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002123 _restrictedEntityFlag[(unsigned char)'&'] = true;
2124 _restrictedEntityFlag[(unsigned char)'<'] = true;
2125 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002127}
2128
2129
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002130void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002131{
2132 va_list va;
2133 va_start( va, format );
2134
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _fp ) {
2136 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
2138 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002139 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 // Close out and re-start the va-args
2141 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002142 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002144 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002145 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002146 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002148 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002149}
2150
2151
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002152void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 for( int i=0; i<depth; ++i ) {
2155 Print( " " );
2156 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002157}
2158
2159
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002160void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 // Look for runs of bytes between entities to print.
2163 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002164
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002166 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002168 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 // Remember, char is sometimes signed. (How many times has that bitten me?)
2170 if ( *q > 0 && *q < ENTITY_RANGE ) {
2171 // Check for entities. If one is found, flush
2172 // the stream up until the entity, write the
2173 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002174 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002176 const size_t delta = q - p;
2177 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002178 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002179 Print( "%.*s", toPrint, p );
2180 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002182 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 for( int i=0; i<NUM_ENTITIES; ++i ) {
2184 if ( entities[i].value == *q ) {
2185 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002186 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 break;
2188 }
2189 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002190 if ( !entityPatternPrinted ) {
2191 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2192 TIXMLASSERT( false );
2193 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 ++p;
2195 }
2196 }
2197 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002198 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 }
2200 }
2201 // Flush the remaining string. This will be the entire
2202 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002203 TIXMLASSERT( p <= q );
2204 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 Print( "%s", p );
2206 }
Lee Thomason857b8682012-01-25 17:50:25 -08002207}
2208
U-Stream\Leeae25a442012-02-17 17:48:16 -08002209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002213 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 -07002214 Print( "%s", bom );
2215 }
2216 if ( writeDec ) {
2217 PushDeclaration( "xml version=\"1.0\"" );
2218 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002219}
2220
2221
Uli Kusterer593a33d2014-02-01 12:48:51 +01002222void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002223{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002224 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002226
Uli Kusterer593a33d2014-02-01 12:48:51 +01002227 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002229 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002230 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002233
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 _elementJustOpened = true;
2236 _firstElement = false;
2237 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002238}
2239
2240
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002241void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002242{
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 Print( " %s=\"", name );
2245 PrintString( value, false );
2246 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002247}
2248
2249
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002250void XMLPrinter::PushAttribute( const char* name, int v )
2251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 char buf[BUF_SIZE];
2253 XMLUtil::ToStr( v, buf, BUF_SIZE );
2254 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002255}
2256
2257
2258void XMLPrinter::PushAttribute( const char* name, unsigned v )
2259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 char buf[BUF_SIZE];
2261 XMLUtil::ToStr( v, buf, BUF_SIZE );
2262 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002263}
2264
2265
2266void XMLPrinter::PushAttribute( const char* name, bool v )
2267{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 char buf[BUF_SIZE];
2269 XMLUtil::ToStr( v, buf, BUF_SIZE );
2270 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002271}
2272
2273
2274void XMLPrinter::PushAttribute( const char* name, double v )
2275{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 char buf[BUF_SIZE];
2277 XMLUtil::ToStr( v, buf, BUF_SIZE );
2278 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002279}
2280
2281
Uli Kustererca412e82014-02-01 13:35:05 +01002282void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002283{
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 --_depth;
2285 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002286
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 Print( "/>" );
2289 }
2290 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002291 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002293 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 }
2295 Print( "</%s>", name );
2296 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002297
Lee Thomason624d43f2012-10-12 10:58:48 -07002298 if ( _textDepth == _depth ) {
2299 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 }
Uli Kustererca412e82014-02-01 13:35:05 +01002301 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 Print( "\n" );
2303 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002305}
2306
2307
Dmitry-Mea092bc12014-12-23 17:57:05 +03002308void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002309{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002310 if ( !_elementJustOpened ) {
2311 return;
2312 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002313 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002314 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002315}
2316
2317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002319{
Lee Thomason624d43f2012-10-12 10:58:48 -07002320 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002321
Dmitry-Mea092bc12014-12-23 17:57:05 +03002322 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002324 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 }
2326 else {
2327 PrintString( text, true );
2328 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002329}
2330
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002331void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 char buf[BUF_SIZE];
2334 XMLUtil::ToStr( value, buf, BUF_SIZE );
2335 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002336}
2337
2338
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002339void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 char buf[BUF_SIZE];
2342 XMLUtil::ToStr( value, buf, BUF_SIZE );
2343 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002344}
2345
2346
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002347void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 char buf[BUF_SIZE];
2350 XMLUtil::ToStr( value, buf, BUF_SIZE );
2351 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002352}
2353
2354
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002355void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 char buf[BUF_SIZE];
2358 XMLUtil::ToStr( value, buf, BUF_SIZE );
2359 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002360}
2361
2362
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002363void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 char buf[BUF_SIZE];
2366 XMLUtil::ToStr( value, buf, BUF_SIZE );
2367 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002368}
2369
Lee Thomason5cae8972012-01-24 18:03:07 -08002370
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002371void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002372{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002373 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002380}
Lee Thomason751da522012-02-10 08:50:51 -08002381
2382
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002383void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002384{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002385 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002390 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002391 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002392}
2393
2394
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002395void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002396{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002397 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002398 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002399 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002400 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002401 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002402 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002404}
2405
2406
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002407bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002408{
Lee Thomason624d43f2012-10-12 10:58:48 -07002409 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 if ( doc.HasBOM() ) {
2411 PushHeader( true, false );
2412 }
2413 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002414}
2415
2416
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002417bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002418{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002419 const XMLElement* parentElem = 0;
2420 if ( element.Parent() ) {
2421 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002422 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002423 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002424 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 while ( attribute ) {
2426 PushAttribute( attribute->Name(), attribute->Value() );
2427 attribute = attribute->Next();
2428 }
2429 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002430}
2431
2432
Uli Kustererca412e82014-02-01 13:35:05 +01002433bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002434{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002435 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002437}
2438
2439
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002440bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 PushText( text.Value(), text.CData() );
2443 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002444}
2445
2446
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002447bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002449 PushComment( comment.Value() );
2450 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002451}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002452
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002453bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 PushDeclaration( declaration.Value() );
2456 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002457}
2458
2459
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002460bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 PushUnknown( unknown.Value() );
2463 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002464}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002465
Lee Thomason685b8952012-11-12 13:00:06 -08002466} // namespace tinyxml2
2467