blob: ea8088c1eb780b7e97f437e3c2abc3ad499130ae [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Lee Thomason29658802014-11-27 22:31:11 -0800152 TIXMLASSERT( other->_flags == 0 );
153 TIXMLASSERT( other->_start == 0 );
154 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300155
Lee Thomason29658802014-11-27 22:31:11 -0800156 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300157
Lee Thomason29658802014-11-27 22:31:11 -0800158 other->_flags = _flags;
159 other->_start = _start;
160 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300161
162 _flags = 0;
163 _start = 0;
164 _end = 0;
165}
166
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800167void StrPair::Reset()
168{
Lee Thomason120b3a62012-10-12 10:06:59 -0700169 if ( _flags & NEEDS_DELETE ) {
170 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700171 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700172 _flags = 0;
173 _start = 0;
174 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800175}
176
177
178void StrPair::SetStr( const char* str, int flags )
179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700180 Reset();
181 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300182 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700183 _start = new char[ len+1 ];
184 memcpy( _start, str, len+1 );
185 _end = _start + len;
186 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800187}
188
189
190char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700192 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400194 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 char endChar = *endTag;
196 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700198 // Inner loop of text parsing.
199 while ( *p ) {
200 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
201 Set( start, p, strFlags );
202 return p + length;
203 }
204 ++p;
205 }
206 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800207}
208
209
210char* StrPair::ParseName( char* p )
211{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400212 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 return 0;
214 }
JayXonee525db2014-12-24 04:01:42 -0500215 if ( !XMLUtil::IsNameStartChar( *p ) ) {
216 return 0;
217 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800218
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500220 ++p;
221 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 ++p;
223 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800224
JayXonee525db2014-12-24 04:01:42 -0500225 Set( start, p, 0 );
226 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800227}
228
229
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700230void StrPair::CollapseWhitespace()
231{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400232 // Adjusting _start would cause undefined behavior on delete[]
233 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700235 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700236
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300237 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700238 char* p = _start; // the read pointer
239 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700240
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 while( *p ) {
242 if ( XMLUtil::IsWhiteSpace( *p )) {
243 p = XMLUtil::SkipWhiteSpace( p );
244 if ( *p == 0 ) {
245 break; // don't write to q; this trims the trailing space.
246 }
247 *q = ' ';
248 ++q;
249 }
250 *q = *p;
251 ++q;
252 ++p;
253 }
254 *q = 0;
255 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700256}
257
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800258
Lee Thomasone4422302012-01-20 17:59:50 -0800259const char* StrPair::GetStr()
260{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300261 TIXMLASSERT( _start );
262 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700263 if ( _flags & NEEDS_FLUSH ) {
264 *_end = 0;
265 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800266
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags ) {
268 char* p = _start; // the read pointer
269 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800270
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 while( p < _end ) {
272 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700273 // CR-LF pair becomes LF
274 // CR alone becomes LF
275 // LF-CR becomes LF
276 if ( *(p+1) == LF ) {
277 p += 2;
278 }
279 else {
280 ++p;
281 }
282 *q++ = LF;
283 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700284 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 if ( *(p+1) == CR ) {
286 p += 2;
287 }
288 else {
289 ++p;
290 }
291 *q++ = LF;
292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 // Entities handled by tinyXML2:
295 // - special entities in the entity table [in/out]
296 // - numeric character reference [in]
297 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400300 const int buflen = 10;
301 char buf[buflen] = { 0 };
302 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300303 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
304 if ( adjusted == 0 ) {
305 *q = *p;
306 ++p;
307 ++q;
308 }
309 else {
310 TIXMLASSERT( 0 <= len && len <= buflen );
311 TIXMLASSERT( q + len <= adjusted );
312 p = adjusted;
313 memcpy( q, buf, len );
314 q += len;
315 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 }
317 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300318 bool entityFound = false;
319 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400320 const Entity& entity = entities[i];
321 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
322 && *( p + entity.length + 1 ) == ';' ) {
323 // Found an entity - convert.
324 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400326 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 break;
329 }
330 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300331 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // fixme: treat as error?
333 ++p;
334 ++q;
335 }
336 }
337 }
338 else {
339 *q = *p;
340 ++p;
341 ++q;
342 }
343 }
344 *q = 0;
345 }
346 // The loop below has plenty going on, and this
347 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300348 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 CollapseWhitespace();
350 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700351 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300353 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700354 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800355}
356
Lee Thomason2c85a712012-01-31 08:24:24 -0800357
Lee Thomasone4422302012-01-20 17:59:50 -0800358
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800359
Lee Thomason56bdd022012-02-09 18:16:58 -0800360// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800361
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800362const char* XMLUtil::ReadBOM( const char* p, bool* bom )
363{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300364 TIXMLASSERT( p );
365 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 *bom = false;
367 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
368 // Check for BOM:
369 if ( *(pu+0) == TIXML_UTF_LEAD_0
370 && *(pu+1) == TIXML_UTF_LEAD_1
371 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
372 *bom = true;
373 p += 3;
374 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300375 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800377}
378
379
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800380void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 const unsigned long BYTE_MASK = 0xBF;
383 const unsigned long BYTE_MARK = 0x80;
384 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 if (input < 0x80) {
387 *length = 1;
388 }
389 else if ( input < 0x800 ) {
390 *length = 2;
391 }
392 else if ( input < 0x10000 ) {
393 *length = 3;
394 }
395 else if ( input < 0x200000 ) {
396 *length = 4;
397 }
398 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300399 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 return;
401 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800404
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 // Scary scary fall throughs.
406 switch (*length) {
407 case 4:
408 --output;
409 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
410 input >>= 6;
411 case 3:
412 --output;
413 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
414 input >>= 6;
415 case 2:
416 --output;
417 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
418 input >>= 6;
419 case 1:
420 --output;
421 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100422 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300423 default:
424 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426}
427
428
429const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 // Presume an entity, and pull it out.
432 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800433
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 if ( *(p+1) == '#' && *(p+2) ) {
435 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300436 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 ptrdiff_t delta = 0;
438 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800439 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800440
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 if ( *(p+2) == 'x' ) {
442 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300443 const char* q = p+3;
444 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 return 0;
446 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800447
Lee Thomason7e67bc82015-01-12 14:05:12 -0800448 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Dmitry-Me9f56e122015-01-12 10:07:54 +0300450 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 return 0;
452 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800453 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800454
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 delta = q-p;
456 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800457
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700459 unsigned int digit = 0;
460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300462 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 }
464 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300465 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 }
467 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300468 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 }
470 else {
471 return 0;
472 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300473 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
475 const unsigned int digitScaled = mult * digit;
476 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
477 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300478 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 mult *= 16;
480 --q;
481 }
482 }
483 else {
484 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300485 const char* q = p+2;
486 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 return 0;
488 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800489
Lee Thomason7e67bc82015-01-12 14:05:12 -0800490 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800491
Dmitry-Me9f56e122015-01-12 10:07:54 +0300492 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 return 0;
494 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800495 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 delta = q-p;
498 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800499
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700500 while ( *q != '#' ) {
501 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300502 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300503 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300504 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
505 const unsigned int digitScaled = mult * digit;
506 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
507 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700508 }
509 else {
510 return 0;
511 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300512 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 mult *= 10;
514 --q;
515 }
516 }
517 // convert the UCS to UTF-8
518 ConvertUTF32ToUTF8( ucs, value, length );
519 return p + delta + 1;
520 }
521 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800522}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800523
524
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700525void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700526{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700528}
529
530
531void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
537void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700540}
541
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800542/*
543 ToStr() of a number is a very tricky topic.
544 https://github.com/leethomason/tinyxml2/issues/106
545*/
Lee Thomason21be8822012-07-15 17:27:22 -0700546void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
547{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800548 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700549}
550
551
552void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
553{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800554 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558bool XMLUtil::ToInt( const char* str, int* value )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
561 return true;
562 }
563 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700564}
565
566bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
569 return true;
570 }
571 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700572}
573
574bool XMLUtil::ToBool( const char* str, bool* value )
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 int ival = 0;
577 if ( ToInt( str, &ival )) {
578 *value = (ival==0) ? false : true;
579 return true;
580 }
581 if ( StringEqual( str, "true" ) ) {
582 *value = true;
583 return true;
584 }
585 else if ( StringEqual( str, "false" ) ) {
586 *value = false;
587 return true;
588 }
589 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700590}
591
592
593bool XMLUtil::ToFloat( const char* str, float* value )
594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
596 return true;
597 }
598 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700599}
600
601bool XMLUtil::ToDouble( const char* str, double* value )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
604 return true;
605 }
606 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700607}
608
609
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700610char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800611{
Dmitry-Me02384662015-03-03 16:02:13 +0300612 TIXMLASSERT( node );
613 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400614 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300616 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300617 *node = 0;
618 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 return p;
620 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800621
Dmitry-Me962083b2015-05-26 11:38:30 +0300622 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 static const char* xmlHeader = { "<?" };
624 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300626 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800628
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 static const int xmlHeaderLen = 2;
630 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300632 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
636 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400637 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300639 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
641 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 p += xmlHeaderLen;
643 }
644 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300645 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 returnNode = new (_commentPool.Alloc()) XMLComment( this );
647 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 p += commentHeaderLen;
649 }
650 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300651 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 p += cdataHeaderLen;
656 text->SetCData( true );
657 }
658 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300659 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
661 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 p += dtdHeaderLen;
663 }
664 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300665 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 returnNode = new (_elementPool.Alloc()) XMLElement( this );
667 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 p += elementHeaderLen;
669 }
670 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300671 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 returnNode = new (_textPool.Alloc()) XMLText( this );
673 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 p = start; // Back it up, all the text counts.
675 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Dmitry-Me02384662015-03-03 16:02:13 +0300677 TIXMLASSERT( returnNode );
678 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 *node = returnNode;
680 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681}
682
683
Lee Thomason751da522012-02-10 08:50:51 -0800684bool XMLDocument::Accept( XMLVisitor* visitor ) const
685{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300686 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 if ( visitor->VisitEnter( *this ) ) {
688 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
689 if ( !node->Accept( visitor ) ) {
690 break;
691 }
692 }
693 }
694 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800695}
Lee Thomason56bdd022012-02-09 18:16:58 -0800696
697
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698// --------- XMLNode ----------- //
699
700XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 _document( doc ),
702 _parent( 0 ),
703 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200704 _prev( 0 ), _next( 0 ),
705 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707}
708
709
710XMLNode::~XMLNode()
711{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 if ( _parent ) {
714 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800716}
717
Michael Daumling21626882013-10-22 17:03:37 +0200718const char* XMLNode::Value() const
719{
Lee Thomason85492022015-05-22 11:07:45 -0700720 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530721 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530722 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200723 return _value.GetStr();
724}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800725
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800726void XMLNode::SetValue( const char* str, bool staticMem )
727{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 }
731 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800734}
735
736
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800737void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800738{
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300740 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700744
Dmitry-Mee3225b12014-09-03 11:03:11 +0400745 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700746 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800748}
749
750
751void XMLNode::Unlink( XMLNode* child )
752{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300753 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300754 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300755 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 if ( child == _firstChild ) {
757 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 if ( child == _lastChild ) {
760 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 }
Lee Thomasond923c672012-01-23 08:44:25 -0800762
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 if ( child->_prev ) {
764 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700766 if ( child->_next ) {
767 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700769 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800770}
771
772
U-Stream\Leeae25a442012-02-17 17:48:16 -0800773void XMLNode::DeleteChild( XMLNode* node )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400778 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800779}
780
781
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800782XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
783{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300784 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300785 if ( addThis->_document != _document ) {
786 TIXMLASSERT( false );
787 return 0;
788 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800789 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700790
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 if ( _lastChild ) {
792 TIXMLASSERT( _firstChild );
793 TIXMLASSERT( _lastChild->_next == 0 );
794 _lastChild->_next = addThis;
795 addThis->_prev = _lastChild;
796 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 }
800 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 TIXMLASSERT( _firstChild == 0 );
802 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800803
Lee Thomason624d43f2012-10-12 10:58:48 -0700804 addThis->_prev = 0;
805 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800809}
810
811
Lee Thomason1ff38e02012-02-14 18:18:16 -0800812XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
813{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300814 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300815 if ( addThis->_document != _document ) {
816 TIXMLASSERT( false );
817 return 0;
818 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800819 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 if ( _firstChild ) {
822 TIXMLASSERT( _lastChild );
823 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800824
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 _firstChild->_prev = addThis;
826 addThis->_next = _firstChild;
827 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800828
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 }
831 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 TIXMLASSERT( _lastChild == 0 );
833 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800834
Lee Thomason624d43f2012-10-12 10:58:48 -0700835 addThis->_prev = 0;
836 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400839 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800840}
841
842
843XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
844{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300845 TIXMLASSERT( addThis );
846 if ( addThis->_document != _document ) {
847 TIXMLASSERT( false );
848 return 0;
849 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700850
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700852
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300854 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 return 0;
856 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 // The last node or the only node.
860 return InsertEndChild( addThis );
861 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800862 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 addThis->_prev = afterThis;
864 addThis->_next = afterThis->_next;
865 afterThis->_next->_prev = addThis;
866 afterThis->_next = addThis;
867 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800869}
870
871
872
873
Dmitry-Me886ad972015-07-22 11:00:51 +0300874const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800875{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300876 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
877 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300879 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 return element;
881 }
882 }
883 }
884 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800885}
886
887
Dmitry-Me886ad972015-07-22 11:00:51 +0300888const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800889{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300890 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
891 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300893 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 return element;
895 }
896 }
897 }
898 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800899}
900
901
Dmitry-Me886ad972015-07-22 11:00:51 +0300902const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800903{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300904 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400905 const XMLElement* element = node->ToElement();
906 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300907 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400908 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 }
910 }
911 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800912}
913
914
Dmitry-Me886ad972015-07-22 11:00:51 +0300915const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800916{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300917 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400918 const XMLElement* element = node->ToElement();
919 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300920 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400921 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 }
923 }
924 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800925}
926
927
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800928char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800929{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 // This is a recursive method, but thinking about it "at the current level"
931 // it is a pretty simple flat list:
932 // <foo/>
933 // <!-- comment -->
934 //
935 // With a special case:
936 // <foo>
937 // </foo>
938 // <!-- comment -->
939 //
940 // Where the closing element (/foo) *must* be the next thing after the opening
941 // element, and the names must match. BUT the tricky bit is that the closing
942 // element will be read by the child.
943 //
944 // 'endTag' is the end tag for this node, it is returned by a call to a child.
945 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800946
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 while( p && *p ) {
948 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800949
Lee Thomason624d43f2012-10-12 10:58:48 -0700950 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300951 if ( node == 0 ) {
952 break;
953 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 StrPair endTag;
956 p = node->ParseDeep( p, &endTag );
957 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400958 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 if ( !_document->Error() ) {
960 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 }
962 break;
963 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530965 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530966 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530967 // A declaration can only be the first child of a document.
968 // Set error, if document already has children.
969 if ( !_document->NoChildren() ) {
970 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
971 DeleteNode( decl );
972 break;
973 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530974 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530975
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400976 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500978 // We read the end tag. Return it to the parent.
979 if ( ele->ClosingType() == XMLElement::CLOSING ) {
980 if ( parentEnd ) {
981 ele->_value.TransferTo( parentEnd );
982 }
983 node->_memPool->SetTracked(); // created and then immediately deleted.
984 DeleteNode( node );
985 return p;
986 }
987
988 // Handle an end tag returned to this level.
989 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400990 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300991 if ( endTag.Empty() ) {
992 if ( ele->ClosingType() == XMLElement::OPEN ) {
993 mismatch = true;
994 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300996 else {
997 if ( ele->ClosingType() != XMLElement::OPEN ) {
998 mismatch = true;
999 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001000 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001001 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 }
1003 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001004 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001005 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001006 DeleteNode( node );
1007 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001008 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 }
JayXondbfdd8f2014-12-12 20:07:14 -05001010 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
1012 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001013}
1014
Dmitry-Mee3225b12014-09-03 11:03:11 +04001015void XMLNode::DeleteNode( XMLNode* node )
1016{
1017 if ( node == 0 ) {
1018 return;
1019 }
1020 MemPool* pool = node->_memPool;
1021 node->~XMLNode();
1022 pool->Free( node );
1023}
1024
Lee Thomason3cebdc42015-01-05 17:16:28 -08001025void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001026{
1027 TIXMLASSERT( insertThis );
1028 TIXMLASSERT( insertThis->_document == _document );
1029
1030 if ( insertThis->_parent )
1031 insertThis->_parent->Unlink( insertThis );
1032 else
1033 insertThis->_memPool->SetTracked();
1034}
1035
Lee Thomason5492a1c2012-01-23 15:32:10 -08001036// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001037char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 const char* start = p;
1040 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001041 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 }
1045 return p;
1046 }
1047 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1049 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001050 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001052
Lee Thomason624d43f2012-10-12 10:58:48 -07001053 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 if ( p && *p ) {
1055 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001056 }
1057 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001058 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 }
1060 }
1061 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001062}
1063
1064
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001065XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1066{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001068 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 }
1070 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1071 text->SetCData( this->CData() );
1072 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001073}
1074
1075
1076bool XMLText::ShallowEqual( const XMLNode* compare ) const
1077{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001078 const XMLText* text = compare->ToText();
1079 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001080}
1081
1082
Lee Thomason56bdd022012-02-09 18:16:58 -08001083bool XMLText::Accept( XMLVisitor* visitor ) const
1084{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001085 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001087}
1088
1089
Lee Thomason3f57d272012-01-11 15:30:03 -08001090// --------- XMLComment ---------- //
1091
Lee Thomasone4422302012-01-20 17:59:50 -08001092XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001093{
1094}
1095
1096
Lee Thomasonce0763e2012-01-11 15:43:54 -08001097XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001098{
Lee Thomason3f57d272012-01-11 15:30:03 -08001099}
1100
1101
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001102char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 // Comment parses as text.
1105 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
1110 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001111}
1112
1113
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001114XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001117 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 }
1119 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1120 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001121}
1122
1123
1124bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1125{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001126 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001127 const XMLComment* comment = compare->ToComment();
1128 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001129}
1130
1131
Lee Thomason751da522012-02-10 08:50:51 -08001132bool XMLComment::Accept( XMLVisitor* visitor ) const
1133{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001134 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001136}
Lee Thomason56bdd022012-02-09 18:16:58 -08001137
1138
Lee Thomason50f97b22012-02-11 16:33:40 -08001139// --------- XMLDeclaration ---------- //
1140
1141XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1142{
1143}
1144
1145
1146XMLDeclaration::~XMLDeclaration()
1147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001149}
1150
1151
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001152char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 // Declaration parses as text.
1155 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001156 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 }
1160 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001161}
1162
1163
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001164XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 }
1169 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1170 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001171}
1172
1173
1174bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1175{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001176 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001177 const XMLDeclaration* declaration = compare->ToDeclaration();
1178 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001179}
1180
1181
1182
Lee Thomason50f97b22012-02-11 16:33:40 -08001183bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1184{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001185 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001187}
1188
1189// --------- XMLUnknown ---------- //
1190
1191XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1192{
1193}
1194
1195
1196XMLUnknown::~XMLUnknown()
1197{
1198}
1199
1200
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001201char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 // Unknown parses as text.
1204 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001205
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 }
1210 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001211}
1212
1213
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001214XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1215{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 }
1219 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1220 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001221}
1222
1223
1224bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1225{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001226 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001227 const XMLUnknown* unknown = compare->ToUnknown();
1228 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001229}
1230
1231
Lee Thomason50f97b22012-02-11 16:33:40 -08001232bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1233{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001234 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001236}
1237
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001238// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001239
1240const char* XMLAttribute::Name() const
1241{
1242 return _name.GetStr();
1243}
1244
1245const char* XMLAttribute::Value() const
1246{
1247 return _value.GetStr();
1248}
1249
Lee Thomason6f381b72012-03-02 12:59:39 -08001250char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001253 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 if ( !p || !*p ) {
1255 return 0;
1256 }
Lee Thomason22aead12012-01-23 13:29:35 -08001257
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 // Skip white space before =
1259 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001260 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 return 0;
1262 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001263
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 ++p; // move up to opening quote
1265 p = XMLUtil::SkipWhiteSpace( p );
1266 if ( *p != '\"' && *p != '\'' ) {
1267 return 0;
1268 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001269
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 char endTag[2] = { *p, 0 };
1271 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001272
Lee Thomason624d43f2012-10-12 10:58:48 -07001273 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001275}
1276
1277
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001278void XMLAttribute::SetName( const char* n )
1279{
Lee Thomason624d43f2012-10-12 10:58:48 -07001280 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001281}
1282
1283
Lee Thomason2fa81722012-11-09 12:37:46 -08001284XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( XMLUtil::ToInt( Value(), value )) {
1287 return XML_NO_ERROR;
1288 }
1289 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001290}
1291
1292
Lee Thomason2fa81722012-11-09 12:37:46 -08001293XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 if ( XMLUtil::ToUnsigned( Value(), value )) {
1296 return XML_NO_ERROR;
1297 }
1298 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001299}
1300
1301
Lee Thomason2fa81722012-11-09 12:37:46 -08001302XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 if ( XMLUtil::ToBool( Value(), value )) {
1305 return XML_NO_ERROR;
1306 }
1307 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001308}
1309
1310
Lee Thomason2fa81722012-11-09 12:37:46 -08001311XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 if ( XMLUtil::ToFloat( Value(), value )) {
1314 return XML_NO_ERROR;
1315 }
1316 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001317}
1318
1319
Lee Thomason2fa81722012-11-09 12:37:46 -08001320XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 if ( XMLUtil::ToDouble( Value(), value )) {
1323 return XML_NO_ERROR;
1324 }
1325 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001326}
1327
1328
1329void XMLAttribute::SetAttribute( const char* v )
1330{
Lee Thomason624d43f2012-10-12 10:58:48 -07001331 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001332}
1333
1334
Lee Thomason1ff38e02012-02-14 18:18:16 -08001335void XMLAttribute::SetAttribute( int v )
1336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001339 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001340}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001341
1342
1343void XMLAttribute::SetAttribute( unsigned v )
1344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 char buf[BUF_SIZE];
1346 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001347 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001348}
1349
1350
1351void XMLAttribute::SetAttribute( bool v )
1352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 char buf[BUF_SIZE];
1354 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001355 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001356}
1357
1358void XMLAttribute::SetAttribute( double v )
1359{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 char buf[BUF_SIZE];
1361 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001362 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001363}
1364
1365void XMLAttribute::SetAttribute( float v )
1366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 char buf[BUF_SIZE];
1368 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001370}
1371
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001372
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001373// --------- XMLElement ---------- //
1374XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 _closingType( 0 ),
1376 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001377{
1378}
1379
1380
1381XMLElement::~XMLElement()
1382{
Lee Thomason624d43f2012-10-12 10:58:48 -07001383 while( _rootAttribute ) {
1384 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001385 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001388}
1389
1390
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001391const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1392{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001393 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1395 return a;
1396 }
1397 }
1398 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001399}
1400
1401
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001402const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 const XMLAttribute* a = FindAttribute( name );
1405 if ( !a ) {
1406 return 0;
1407 }
1408 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1409 return a->Value();
1410 }
1411 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001412}
1413
1414
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001415const char* XMLElement::GetText() const
1416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001418 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 }
1420 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001421}
1422
1423
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001424void XMLElement::SetText( const char* inText )
1425{
Uli Kusterer869bb592014-01-21 01:36:16 +01001426 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001427 FirstChild()->SetValue( inText );
1428 else {
1429 XMLText* theText = GetDocument()->NewText( inText );
1430 InsertFirstChild( theText );
1431 }
1432}
1433
Lee Thomason5bb2d802014-01-24 10:42:57 -08001434
1435void XMLElement::SetText( int v )
1436{
1437 char buf[BUF_SIZE];
1438 XMLUtil::ToStr( v, buf, BUF_SIZE );
1439 SetText( buf );
1440}
1441
1442
1443void XMLElement::SetText( unsigned v )
1444{
1445 char buf[BUF_SIZE];
1446 XMLUtil::ToStr( v, buf, BUF_SIZE );
1447 SetText( buf );
1448}
1449
1450
1451void XMLElement::SetText( bool v )
1452{
1453 char buf[BUF_SIZE];
1454 XMLUtil::ToStr( v, buf, BUF_SIZE );
1455 SetText( buf );
1456}
1457
1458
1459void XMLElement::SetText( float v )
1460{
1461 char buf[BUF_SIZE];
1462 XMLUtil::ToStr( v, buf, BUF_SIZE );
1463 SetText( buf );
1464}
1465
1466
1467void XMLElement::SetText( double v )
1468{
1469 char buf[BUF_SIZE];
1470 XMLUtil::ToStr( v, buf, BUF_SIZE );
1471 SetText( buf );
1472}
1473
1474
MortenMacFly4ee49f12013-01-14 20:03:14 +01001475XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001478 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001479 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 return XML_SUCCESS;
1481 }
1482 return XML_CAN_NOT_CONVERT_TEXT;
1483 }
1484 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001485}
1486
1487
MortenMacFly4ee49f12013-01-14 20:03:14 +01001488XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001491 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001492 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 return XML_SUCCESS;
1494 }
1495 return XML_CAN_NOT_CONVERT_TEXT;
1496 }
1497 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001498}
1499
1500
MortenMacFly4ee49f12013-01-14 20:03:14 +01001501XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001504 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001505 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 return XML_SUCCESS;
1507 }
1508 return XML_CAN_NOT_CONVERT_TEXT;
1509 }
1510 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001511}
1512
1513
MortenMacFly4ee49f12013-01-14 20:03:14 +01001514XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001515{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001517 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001518 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 return XML_SUCCESS;
1520 }
1521 return XML_CAN_NOT_CONVERT_TEXT;
1522 }
1523 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001524}
1525
1526
MortenMacFly4ee49f12013-01-14 20:03:14 +01001527XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001530 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001531 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 return XML_SUCCESS;
1533 }
1534 return XML_CAN_NOT_CONVERT_TEXT;
1535 }
1536 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001537}
1538
1539
1540
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001541XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 XMLAttribute* last = 0;
1544 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1549 break;
1550 }
1551 }
1552 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001553 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1555 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001557 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 }
1559 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 }
1562 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001563 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 }
1565 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001566}
1567
1568
U-Stream\Leeae25a442012-02-17 17:48:16 -08001569void XMLElement::DeleteAttribute( const char* name )
1570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1574 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 }
1577 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001578 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001580 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 break;
1582 }
1583 prev = a;
1584 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001585}
1586
1587
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001588char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 const char* start = p;
1591 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001592
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 // Read the attributes.
1594 while( p ) {
1595 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001596 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001597 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 return 0;
1599 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001600
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001602 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001603 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1605 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001606 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001607
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001610 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001612 return 0;
1613 }
1614 // There is a minor bug here: if the attribute in the source xml
1615 // document is duplicated, it will not be detected and the
1616 // attribute will be doubly added. However, tracking the 'prevAttribute'
1617 // avoids re-scanning the attribute list. Preferring performance for
1618 // now, may reconsider in the future.
1619 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
1625 prevAttribute = attrib;
1626 }
1627 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 else if ( *p == '>' ) {
1629 ++p;
1630 break;
1631 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001632 // end of the tag
1633 else if ( *p == '/' && *(p+1) == '>' ) {
1634 _closingType = CLOSED;
1635 return p+2; // done; sealed element.
1636 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 return 0;
1640 }
1641 }
1642 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001643}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001644
Dmitry-Mee3225b12014-09-03 11:03:11 +04001645void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1646{
1647 if ( attribute == 0 ) {
1648 return;
1649 }
1650 MemPool* pool = attribute->_memPool;
1651 attribute->~XMLAttribute();
1652 pool->Free( attribute );
1653}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001654
Lee Thomason67d61312012-01-24 16:01:51 -08001655//
1656// <ele></ele>
1657// <ele>foo<b>bar</b></ele>
1658//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001659char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001660{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 // Read the element name.
1662 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001663
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 // The closing element is the </element> form. It is
1665 // parsed just like a regular element then deleted from
1666 // the DOM.
1667 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 ++p;
1670 }
Lee Thomason67d61312012-01-24 16:01:51 -08001671
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 p = _value.ParseName( p );
1673 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 return 0;
1675 }
Lee Thomason67d61312012-01-24 16:01:51 -08001676
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001677 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 return p;
1680 }
Lee Thomason67d61312012-01-24 16:01:51 -08001681
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 p = XMLNode::ParseDeep( p, strPair );
1683 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001684}
1685
1686
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001687
1688XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1689{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001691 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 }
1693 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1694 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1695 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1696 }
1697 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001698}
1699
1700
1701bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1702{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001703 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001705 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001706
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 const XMLAttribute* a=FirstAttribute();
1708 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001709
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 while ( a && b ) {
1711 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1712 return false;
1713 }
1714 a = a->Next();
1715 b = b->Next();
1716 }
1717 if ( a || b ) {
1718 // different count
1719 return false;
1720 }
1721 return true;
1722 }
1723 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001724}
1725
1726
Lee Thomason751da522012-02-10 08:50:51 -08001727bool XMLElement::Accept( XMLVisitor* visitor ) const
1728{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001729 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1732 if ( !node->Accept( visitor ) ) {
1733 break;
1734 }
1735 }
1736 }
1737 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001738}
Lee Thomason56bdd022012-02-09 18:16:58 -08001739
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001740
Lee Thomason3f57d272012-01-11 15:30:03 -08001741// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001742
1743// Warning: List must match 'enum XMLError'
1744const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1745 "XML_SUCCESS",
1746 "XML_NO_ATTRIBUTE",
1747 "XML_WRONG_ATTRIBUTE_TYPE",
1748 "XML_ERROR_FILE_NOT_FOUND",
1749 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1750 "XML_ERROR_FILE_READ_ERROR",
1751 "XML_ERROR_ELEMENT_MISMATCH",
1752 "XML_ERROR_PARSING_ELEMENT",
1753 "XML_ERROR_PARSING_ATTRIBUTE",
1754 "XML_ERROR_IDENTIFYING_TAG",
1755 "XML_ERROR_PARSING_TEXT",
1756 "XML_ERROR_PARSING_CDATA",
1757 "XML_ERROR_PARSING_COMMENT",
1758 "XML_ERROR_PARSING_DECLARATION",
1759 "XML_ERROR_PARSING_UNKNOWN",
1760 "XML_ERROR_EMPTY_DOCUMENT",
1761 "XML_ERROR_MISMATCHED_ELEMENT",
1762 "XML_ERROR_PARSING",
1763 "XML_CAN_NOT_CONVERT_TEXT",
1764 "XML_NO_TEXT_NODE"
1765};
1766
1767
Lee Thomason624d43f2012-10-12 10:58:48 -07001768XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 _writeBOM( false ),
1771 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001772 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 _whitespace( whitespace ),
1774 _errorStr1( 0 ),
1775 _errorStr2( 0 ),
1776 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001777{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001778 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1779 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001780}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001781
1782
Lee Thomason3f57d272012-01-11 15:30:03 -08001783XMLDocument::~XMLDocument()
1784{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001785 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001786}
1787
1788
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001789void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001790{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001791 DeleteChildren();
1792
Dmitry-Meab37df82014-11-28 12:08:36 +03001793#ifdef DEBUG
1794 const bool hadError = Error();
1795#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 _errorID = XML_NO_ERROR;
1797 _errorStr1 = 0;
1798 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001799
Lee Thomason624d43f2012-10-12 10:58:48 -07001800 delete [] _charBuffer;
1801 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001802
1803#if 0
1804 _textPool.Trace( "text" );
1805 _elementPool.Trace( "element" );
1806 _commentPool.Trace( "comment" );
1807 _attributePool.Trace( "attribute" );
1808#endif
1809
1810#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001811 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001812 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1813 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1814 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1815 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1816 }
1817#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001818}
1819
Lee Thomason3f57d272012-01-11 15:30:03 -08001820
Lee Thomason2c85a712012-01-31 08:24:24 -08001821XMLElement* XMLDocument::NewElement( const char* name )
1822{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001823 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1825 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 ele->SetName( name );
1827 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001828}
1829
1830
Lee Thomason1ff38e02012-02-14 18:18:16 -08001831XMLComment* XMLDocument::NewComment( const char* str )
1832{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001833 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1835 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 comment->SetValue( str );
1837 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001838}
1839
1840
1841XMLText* XMLDocument::NewText( const char* str )
1842{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001843 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1845 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 text->SetValue( str );
1847 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001848}
1849
1850
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001851XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1852{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001853 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1855 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1857 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001858}
1859
1860
1861XMLUnknown* XMLDocument::NewUnknown( const char* str )
1862{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001863 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1865 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 unk->SetValue( str );
1867 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001868}
1869
Dmitry-Me01578db2014-08-19 10:18:48 +04001870static FILE* callfopen( const char* filepath, const char* mode )
1871{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001872 TIXMLASSERT( filepath );
1873 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001874#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1875 FILE* fp = 0;
1876 errno_t err = fopen_s( &fp, filepath, mode );
1877 if ( err ) {
1878 return 0;
1879 }
1880#else
1881 FILE* fp = fopen( filepath, mode );
1882#endif
1883 return fp;
1884}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001885
1886void XMLDocument::DeleteNode( XMLNode* node ) {
1887 TIXMLASSERT( node );
1888 TIXMLASSERT(node->_document == this );
1889 if (node->_parent) {
1890 node->_parent->DeleteChild( node );
1891 }
1892 else {
1893 // Isn't in the tree.
1894 // Use the parent delete.
1895 // Also, we need to mark it tracked: we 'know'
1896 // it was never used.
1897 node->_memPool->SetTracked();
1898 // Call the static XMLNode version:
1899 XMLNode::DeleteNode(node);
1900 }
1901}
1902
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001903
Lee Thomason2fa81722012-11-09 12:37:46 -08001904XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001905{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001906 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001907 FILE* fp = callfopen( filename, "rb" );
1908 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 }
1912 LoadFile( fp );
1913 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001915}
1916
Dmitry-Me901fed52015-09-25 10:29:51 +03001917// This is likely overengineered template art to have a check that unsigned long value incremented
1918// by one still fits into size_t. If size_t type is larger than unsigned long type
1919// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1920// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1921// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1922// types sizes relate to each other.
1923template
1924<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1925struct LongFitsIntoSizeTMinusOne {
1926 static bool Fits( unsigned long value )
1927 {
1928 return value < (size_t)-1;
1929 }
1930};
1931
1932template <>
1933bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1934{
1935 return true;
1936}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001937
Lee Thomason2fa81722012-11-09 12:37:46 -08001938XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001939{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001940 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001942 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001943 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001944 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1945 return _errorID;
1946 }
1947
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001949 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001951 if ( filelength == -1L ) {
1952 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1953 return _errorID;
1954 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955
Dmitry-Me901fed52015-09-25 10:29:51 +03001956 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001957 // Cannot handle files which won't fit in buffer together with null terminator
1958 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1959 return _errorID;
1960 }
1961
Dmitry-Me72801b82015-05-07 09:41:39 +03001962 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001963 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001966
Dmitry-Me72801b82015-05-07 09:41:39 +03001967 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03001968 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 _charBuffer = new char[size+1];
1970 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 if ( read != size ) {
1972 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001973 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001975
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977
Dmitry-Me97476b72015-01-01 16:15:57 +03001978 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001980}
1981
1982
Lee Thomason2fa81722012-11-09 12:37:46 -08001983XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001984{
Dmitry-Me01578db2014-08-19 10:18:48 +04001985 FILE* fp = callfopen( filename, "w" );
1986 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 }
1990 SaveFile(fp, compact);
1991 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001992 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001993}
1994
1995
Lee Thomason2fa81722012-11-09 12:37:46 -08001996XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001997{
Ant Mitchell189198f2015-03-24 16:20:36 +00001998 // Clear any error from the last save, otherwise it will get reported
1999 // for *this* call.
2000 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 XMLPrinter stream( fp, compact );
2002 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002003 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002004}
2005
Lee Thomason1ff38e02012-02-14 18:18:16 -08002006
Lee Thomason2fa81722012-11-09 12:37:46 -08002007XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002008{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002009 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002010
Lee Thomason82d32002014-02-21 22:47:18 -08002011 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 }
2015 if ( len == (size_t)(-1) ) {
2016 len = strlen( p );
2017 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002018 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 _charBuffer = new char[ len+1 ];
2020 memcpy( _charBuffer, p, len );
2021 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002022
Dmitry-Me97476b72015-01-01 16:15:57 +03002023 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002024 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002025 // clean up now essentially dangling memory.
2026 // and the parse fail can put objects in the
2027 // pools that are dead and inaccessible.
2028 DeleteChildren();
2029 _elementPool.Clear();
2030 _attributePool.Clear();
2031 _textPool.Clear();
2032 _commentPool.Clear();
2033 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002035}
2036
2037
PKEuS1c5f99e2013-07-06 11:28:39 +02002038void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002039{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002040 if ( streamer ) {
2041 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002043 else {
2044 XMLPrinter stdoutStreamer( stdout );
2045 Accept( &stdoutStreamer );
2046 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002047}
2048
2049
Lee Thomason2fa81722012-11-09 12:37:46 -08002050void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002051{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002052 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 _errorID = error;
2054 _errorStr1 = str1;
2055 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002056}
2057
Lee Thomason331596e2014-09-11 14:56:43 -07002058const char* XMLDocument::ErrorName() const
2059{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002060 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002061 const char* errorName = _errorNames[_errorID];
2062 TIXMLASSERT( errorName && errorName[0] );
2063 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002064}
Lee Thomason5cae8972012-01-24 18:03:07 -08002065
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002066void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002067{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002068 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 static const int LEN = 20;
2070 char buf1[LEN] = { 0 };
2071 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002072
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( _errorStr1 ) {
2074 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 if ( _errorStr2 ) {
2077 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002079
Dmitry-Me2ad43202015-04-16 12:18:58 +03002080 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2081 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2082 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002083 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002084 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086}
2087
Dmitry-Me97476b72015-01-01 16:15:57 +03002088void XMLDocument::Parse()
2089{
2090 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2091 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002092 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002093 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002094 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002095 if ( !*p ) {
2096 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2097 return;
2098 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002099 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002100}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002101
PKEuS1bfb9542013-08-04 13:51:17 +02002102XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002103 _elementJustOpened( false ),
2104 _firstElement( true ),
2105 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002106 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 _textDepth( -1 ),
2108 _processEntities( true ),
2109 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 _entityFlag[i] = false;
2113 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 }
2115 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002116 const char entityValue = entities[i].value;
2117 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2118 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002120 _restrictedEntityFlag[(unsigned char)'&'] = true;
2121 _restrictedEntityFlag[(unsigned char)'<'] = true;
2122 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002124}
2125
2126
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002127void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002128{
2129 va_list va;
2130 va_start( va, format );
2131
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 if ( _fp ) {
2133 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 }
2135 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002136 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 // Close out and re-start the va-args
2138 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002139 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002141 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002142 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002143 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002145 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002146}
2147
2148
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002149void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 for( int i=0; i<depth; ++i ) {
2152 Print( " " );
2153 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002154}
2155
2156
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002157void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 // Look for runs of bytes between entities to print.
2160 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002161
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002163 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002165 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 // Remember, char is sometimes signed. (How many times has that bitten me?)
2167 if ( *q > 0 && *q < ENTITY_RANGE ) {
2168 // Check for entities. If one is found, flush
2169 // the stream up until the entity, write the
2170 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002171 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002173 const size_t delta = q - p;
2174 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002175 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002176 Print( "%.*s", toPrint, p );
2177 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002179 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 for( int i=0; i<NUM_ENTITIES; ++i ) {
2181 if ( entities[i].value == *q ) {
2182 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002183 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 break;
2185 }
2186 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002187 if ( !entityPatternPrinted ) {
2188 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2189 TIXMLASSERT( false );
2190 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 ++p;
2192 }
2193 }
2194 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002195 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 }
2197 }
2198 // Flush the remaining string. This will be the entire
2199 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002200 TIXMLASSERT( p <= q );
2201 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "%s", p );
2203 }
Lee Thomason857b8682012-01-25 17:50:25 -08002204}
2205
U-Stream\Leeae25a442012-02-17 17:48:16 -08002206
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002207void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002210 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 -07002211 Print( "%s", bom );
2212 }
2213 if ( writeDec ) {
2214 PushDeclaration( "xml version=\"1.0\"" );
2215 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002216}
2217
2218
Uli Kusterer593a33d2014-02-01 12:48:51 +01002219void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002220{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002221 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002223
Uli Kusterer593a33d2014-02-01 12:48:51 +01002224 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002226 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002227 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002230
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 _elementJustOpened = true;
2233 _firstElement = false;
2234 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002235}
2236
2237
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002238void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002239{
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 Print( " %s=\"", name );
2242 PrintString( value, false );
2243 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002244}
2245
2246
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002247void XMLPrinter::PushAttribute( const char* name, int v )
2248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 char buf[BUF_SIZE];
2250 XMLUtil::ToStr( v, buf, BUF_SIZE );
2251 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002252}
2253
2254
2255void XMLPrinter::PushAttribute( const char* name, unsigned v )
2256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 char buf[BUF_SIZE];
2258 XMLUtil::ToStr( v, buf, BUF_SIZE );
2259 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002260}
2261
2262
2263void XMLPrinter::PushAttribute( const char* name, bool v )
2264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 char buf[BUF_SIZE];
2266 XMLUtil::ToStr( v, buf, BUF_SIZE );
2267 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002268}
2269
2270
2271void XMLPrinter::PushAttribute( const char* name, double v )
2272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 char buf[BUF_SIZE];
2274 XMLUtil::ToStr( v, buf, BUF_SIZE );
2275 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002276}
2277
2278
Uli Kustererca412e82014-02-01 13:35:05 +01002279void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002280{
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 --_depth;
2282 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002283
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 Print( "/>" );
2286 }
2287 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002288 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 }
2292 Print( "</%s>", name );
2293 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002294
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 if ( _textDepth == _depth ) {
2296 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 }
Uli Kustererca412e82014-02-01 13:35:05 +01002298 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 Print( "\n" );
2300 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002302}
2303
2304
Dmitry-Mea092bc12014-12-23 17:57:05 +03002305void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002306{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002307 if ( !_elementJustOpened ) {
2308 return;
2309 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002312}
2313
2314
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002315void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002316{
Lee Thomason624d43f2012-10-12 10:58:48 -07002317 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002318
Dmitry-Mea092bc12014-12-23 17:57:05 +03002319 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002321 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 }
2323 else {
2324 PrintString( text, true );
2325 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002326}
2327
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002328void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002329{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002330 char buf[BUF_SIZE];
2331 XMLUtil::ToStr( value, buf, BUF_SIZE );
2332 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002333}
2334
2335
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002336void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002337{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 char buf[BUF_SIZE];
2339 XMLUtil::ToStr( value, buf, BUF_SIZE );
2340 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002341}
2342
2343
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002344void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002346 char buf[BUF_SIZE];
2347 XMLUtil::ToStr( value, buf, BUF_SIZE );
2348 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002349}
2350
2351
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002352void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002354 char buf[BUF_SIZE];
2355 XMLUtil::ToStr( value, buf, BUF_SIZE );
2356 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002357}
2358
2359
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002360void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 char buf[BUF_SIZE];
2363 XMLUtil::ToStr( value, buf, BUF_SIZE );
2364 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002365}
2366
Lee Thomason5cae8972012-01-24 18:03:07 -08002367
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002368void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002369{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002370 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002371 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002374 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002377}
Lee Thomason751da522012-02-10 08:50:51 -08002378
2379
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002380void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002381{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002382 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002383 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002387 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002389}
2390
2391
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002392void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002393{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002394 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002395 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002399 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002401}
2402
2403
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002404bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002405{
Lee Thomason624d43f2012-10-12 10:58:48 -07002406 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 if ( doc.HasBOM() ) {
2408 PushHeader( true, false );
2409 }
2410 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002411}
2412
2413
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002414bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002415{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002416 const XMLElement* parentElem = 0;
2417 if ( element.Parent() ) {
2418 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002419 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002420 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002421 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 while ( attribute ) {
2423 PushAttribute( attribute->Name(), attribute->Value() );
2424 attribute = attribute->Next();
2425 }
2426 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002427}
2428
2429
Uli Kustererca412e82014-02-01 13:35:05 +01002430bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002431{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002432 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002434}
2435
2436
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002437bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 PushText( text.Value(), text.CData() );
2440 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002441}
2442
2443
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002444bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 PushComment( comment.Value() );
2447 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002448}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002449
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002450bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 PushDeclaration( declaration.Value() );
2453 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002454}
2455
2456
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002457bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002459 PushUnknown( unknown.Value() );
2460 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002461}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002462
Lee Thomason685b8952012-11-12 13:00:06 -08002463} // namespace tinyxml2
2464