blob: f2c2e12cd779119ace85c9b55baba87480200ed5 [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 );*/
44 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
45 {
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
53 inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
54 {
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.
71 inline int TIXML_VSCPRINTF( const char* format, va_list va )
72 {
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
94 inline int TIXML_VSCPRINTF( const char* format, va_list va )
95 {
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 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700182 _start = new char[ len+1 ];
183 memcpy( _start, str, len+1 );
184 _end = _start + len;
185 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800186}
187
188
189char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700191 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800192
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400193 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 char endChar = *endTag;
195 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800196
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // Inner loop of text parsing.
198 while ( *p ) {
199 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
200 Set( start, p, strFlags );
201 return p + length;
202 }
203 ++p;
204 }
205 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800206}
207
208
209char* StrPair::ParseName( char* p )
210{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400211 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 return 0;
213 }
JayXonee525db2014-12-24 04:01:42 -0500214 if ( !XMLUtil::IsNameStartChar( *p ) ) {
215 return 0;
216 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800217
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400218 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500219 ++p;
220 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 ++p;
222 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800223
JayXonee525db2014-12-24 04:01:42 -0500224 Set( start, p, 0 );
225 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226}
227
228
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700229void StrPair::CollapseWhitespace()
230{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400231 // Adjusting _start would cause undefined behavior on delete[]
232 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700233 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700234 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700235
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300236 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700237 char* p = _start; // the read pointer
238 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700239
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700240 while( *p ) {
241 if ( XMLUtil::IsWhiteSpace( *p )) {
242 p = XMLUtil::SkipWhiteSpace( p );
243 if ( *p == 0 ) {
244 break; // don't write to q; this trims the trailing space.
245 }
246 *q = ' ';
247 ++q;
248 }
249 *q = *p;
250 ++q;
251 ++p;
252 }
253 *q = 0;
254 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700255}
256
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800257
Lee Thomasone4422302012-01-20 17:59:50 -0800258const char* StrPair::GetStr()
259{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300260 TIXMLASSERT( _start );
261 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700262 if ( _flags & NEEDS_FLUSH ) {
263 *_end = 0;
264 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800265
Lee Thomason120b3a62012-10-12 10:06:59 -0700266 if ( _flags ) {
267 char* p = _start; // the read pointer
268 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800269
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 while( p < _end ) {
271 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700272 // CR-LF pair becomes LF
273 // CR alone becomes LF
274 // LF-CR becomes LF
275 if ( *(p+1) == LF ) {
276 p += 2;
277 }
278 else {
279 ++p;
280 }
281 *q++ = LF;
282 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700283 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 if ( *(p+1) == CR ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
290 *q++ = LF;
291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 // Entities handled by tinyXML2:
294 // - special entities in the entity table [in/out]
295 // - numeric character reference [in]
296 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800297
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400299 const int buflen = 10;
300 char buf[buflen] = { 0 };
301 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300302 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
303 if ( adjusted == 0 ) {
304 *q = *p;
305 ++p;
306 ++q;
307 }
308 else {
309 TIXMLASSERT( 0 <= len && len <= buflen );
310 TIXMLASSERT( q + len <= adjusted );
311 p = adjusted;
312 memcpy( q, buf, len );
313 q += len;
314 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700315 }
316 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300317 bool entityFound = false;
318 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400319 const Entity& entity = entities[i];
320 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
321 && *( p + entity.length + 1 ) == ';' ) {
322 // Found an entity - convert.
323 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400325 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300326 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 break;
328 }
329 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300330 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 // fixme: treat as error?
332 ++p;
333 ++q;
334 }
335 }
336 }
337 else {
338 *q = *p;
339 ++p;
340 ++q;
341 }
342 }
343 *q = 0;
344 }
345 // The loop below has plenty going on, and this
346 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300347 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700348 CollapseWhitespace();
349 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700350 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300352 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700353 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800354}
355
Lee Thomason2c85a712012-01-31 08:24:24 -0800356
Lee Thomasone4422302012-01-20 17:59:50 -0800357
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800358
Lee Thomason56bdd022012-02-09 18:16:58 -0800359// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800360
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800361const char* XMLUtil::ReadBOM( const char* p, bool* bom )
362{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300363 TIXMLASSERT( p );
364 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700365 *bom = false;
366 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
367 // Check for BOM:
368 if ( *(pu+0) == TIXML_UTF_LEAD_0
369 && *(pu+1) == TIXML_UTF_LEAD_1
370 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
371 *bom = true;
372 p += 3;
373 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300374 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700375 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800376}
377
378
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800379void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700381 const unsigned long BYTE_MASK = 0xBF;
382 const unsigned long BYTE_MARK = 0x80;
383 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 if (input < 0x80) {
386 *length = 1;
387 }
388 else if ( input < 0x800 ) {
389 *length = 2;
390 }
391 else if ( input < 0x10000 ) {
392 *length = 3;
393 }
394 else if ( input < 0x200000 ) {
395 *length = 4;
396 }
397 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300398 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return;
400 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800401
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 // Scary scary fall throughs.
405 switch (*length) {
406 case 4:
407 --output;
408 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
409 input >>= 6;
410 case 3:
411 --output;
412 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
413 input >>= 6;
414 case 2:
415 --output;
416 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
417 input >>= 6;
418 case 1:
419 --output;
420 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100421 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300422 default:
423 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425}
426
427
428const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 // Presume an entity, and pull it out.
431 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800432
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 if ( *(p+1) == '#' && *(p+2) ) {
434 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300435 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 ptrdiff_t delta = 0;
437 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800438 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800439
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( *(p+2) == 'x' ) {
441 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300442 const char* q = p+3;
443 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700444 return 0;
445 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800446
Lee Thomason7e67bc82015-01-12 14:05:12 -0800447 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448
Dmitry-Me9f56e122015-01-12 10:07:54 +0300449 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 return 0;
451 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800452 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 delta = q-p;
455 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700458 unsigned int digit = 0;
459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300461 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 }
463 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300464 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 }
466 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300467 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 }
469 else {
470 return 0;
471 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300472 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300473 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
474 const unsigned int digitScaled = mult * digit;
475 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
476 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300477 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 mult *= 16;
479 --q;
480 }
481 }
482 else {
483 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300484 const char* q = p+2;
485 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 return 0;
487 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800488
Lee Thomason7e67bc82015-01-12 14:05:12 -0800489 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800490
Dmitry-Me9f56e122015-01-12 10:07:54 +0300491 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 return 0;
493 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800494 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 delta = q-p;
497 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 while ( *q != '#' ) {
500 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300502 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300503 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
504 const unsigned int digitScaled = mult * digit;
505 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
506 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 }
508 else {
509 return 0;
510 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300511 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 mult *= 10;
513 --q;
514 }
515 }
516 // convert the UCS to UTF-8
517 ConvertUTF32ToUTF8( ucs, value, length );
518 return p + delta + 1;
519 }
520 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800522
523
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700524void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700527}
528
529
530void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700533}
534
535
536void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700539}
540
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800541/*
542 ToStr() of a number is a very tricky topic.
543 https://github.com/leethomason/tinyxml2/issues/106
544*/
Lee Thomason21be8822012-07-15 17:27:22 -0700545void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
546{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800547 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700548}
549
550
551void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
552{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800553 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700554}
555
556
557bool XMLUtil::ToInt( const char* str, int* value )
558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
560 return true;
561 }
562 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700563}
564
565bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
568 return true;
569 }
570 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573bool XMLUtil::ToBool( const char* str, bool* value )
574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 int ival = 0;
576 if ( ToInt( str, &ival )) {
577 *value = (ival==0) ? false : true;
578 return true;
579 }
580 if ( StringEqual( str, "true" ) ) {
581 *value = true;
582 return true;
583 }
584 else if ( StringEqual( str, "false" ) ) {
585 *value = false;
586 return true;
587 }
588 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700589}
590
591
592bool XMLUtil::ToFloat( const char* str, float* value )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600bool XMLUtil::ToDouble( const char* str, double* value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700609char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800610{
Dmitry-Me02384662015-03-03 16:02:13 +0300611 TIXMLASSERT( node );
612 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400613 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300615 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300616 *node = 0;
617 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 return p;
619 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800620
Dmitry-Me962083b2015-05-26 11:38:30 +0300621 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 static const char* xmlHeader = { "<?" };
623 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300625 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 static const int xmlHeaderLen = 2;
629 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300631 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800633
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
635 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400636 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300638 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
640 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 p += xmlHeaderLen;
642 }
643 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300644 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 returnNode = new (_commentPool.Alloc()) XMLComment( this );
646 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 p += commentHeaderLen;
648 }
649 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300650 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 p += cdataHeaderLen;
655 text->SetCData( true );
656 }
657 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300658 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
660 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 p += dtdHeaderLen;
662 }
663 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300664 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 returnNode = new (_elementPool.Alloc()) XMLElement( this );
666 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 p += elementHeaderLen;
668 }
669 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300670 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode = new (_textPool.Alloc()) XMLText( this );
672 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 p = start; // Back it up, all the text counts.
674 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Dmitry-Me02384662015-03-03 16:02:13 +0300676 TIXMLASSERT( returnNode );
677 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 *node = returnNode;
679 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680}
681
682
Lee Thomason751da522012-02-10 08:50:51 -0800683bool XMLDocument::Accept( XMLVisitor* visitor ) const
684{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300685 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 if ( visitor->VisitEnter( *this ) ) {
687 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
688 if ( !node->Accept( visitor ) ) {
689 break;
690 }
691 }
692 }
693 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800694}
Lee Thomason56bdd022012-02-09 18:16:58 -0800695
696
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697// --------- XMLNode ----------- //
698
699XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 _document( doc ),
701 _parent( 0 ),
702 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200703 _prev( 0 ), _next( 0 ),
704 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800705{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706}
707
708
709XMLNode::~XMLNode()
710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700712 if ( _parent ) {
713 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800715}
716
Michael Daumling21626882013-10-22 17:03:37 +0200717const char* XMLNode::Value() const
718{
Lee Thomason85492022015-05-22 11:07:45 -0700719 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530720 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530721 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200722 return _value.GetStr();
723}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800724
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800725void XMLNode::SetValue( const char* str, bool staticMem )
726{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 }
730 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800733}
734
735
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800736void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800737{
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300739 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700742 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700743
Dmitry-Mee3225b12014-09-03 11:03:11 +0400744 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700745 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800747}
748
749
750void XMLNode::Unlink( XMLNode* child )
751{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300752 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300753 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300754 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 if ( child == _firstChild ) {
756 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 if ( child == _lastChild ) {
759 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 }
Lee Thomasond923c672012-01-23 08:44:25 -0800761
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 if ( child->_prev ) {
763 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 if ( child->_next ) {
766 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700768 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800769}
770
771
U-Stream\Leeae25a442012-02-17 17:48:16 -0800772void XMLNode::DeleteChild( XMLNode* node )
773{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300774 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300775 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400777 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800778}
779
780
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800781XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
782{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300783 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300784 if ( addThis->_document != _document ) {
785 TIXMLASSERT( false );
786 return 0;
787 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800788 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700789
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 if ( _lastChild ) {
791 TIXMLASSERT( _firstChild );
792 TIXMLASSERT( _lastChild->_next == 0 );
793 _lastChild->_next = addThis;
794 addThis->_prev = _lastChild;
795 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800796
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
799 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 TIXMLASSERT( _firstChild == 0 );
801 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800802
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 addThis->_prev = 0;
804 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800808}
809
810
Lee Thomason1ff38e02012-02-14 18:18:16 -0800811XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
812{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300813 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300814 if ( addThis->_document != _document ) {
815 TIXMLASSERT( false );
816 return 0;
817 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800818 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700819
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 if ( _firstChild ) {
821 TIXMLASSERT( _lastChild );
822 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800823
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 _firstChild->_prev = addThis;
825 addThis->_next = _firstChild;
826 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800827
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
830 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 TIXMLASSERT( _lastChild == 0 );
832 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800833
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 addThis->_prev = 0;
835 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400838 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800839}
840
841
842XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
843{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300844 TIXMLASSERT( addThis );
845 if ( addThis->_document != _document ) {
846 TIXMLASSERT( false );
847 return 0;
848 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700849
Dmitry-Meabb2d042014-12-09 12:59:31 +0300850 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300853 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 return 0;
855 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 // The last node or the only node.
859 return InsertEndChild( addThis );
860 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800861 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 addThis->_prev = afterThis;
863 addThis->_next = afterThis->_next;
864 afterThis->_next->_prev = addThis;
865 afterThis->_next = addThis;
866 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800868}
869
870
871
872
Dmitry-Me886ad972015-07-22 11:00:51 +0300873const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800874{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300875 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
876 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300878 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 return element;
880 }
881 }
882 }
883 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800884}
885
886
Dmitry-Me886ad972015-07-22 11:00:51 +0300887const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800888{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300889 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
890 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300892 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 return element;
894 }
895 }
896 }
897 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800898}
899
900
Dmitry-Me886ad972015-07-22 11:00:51 +0300901const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800902{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300903 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400904 const XMLElement* element = node->ToElement();
905 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300906 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400907 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 }
909 }
910 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
Dmitry-Me886ad972015-07-22 11:00:51 +0300914const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800915{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300916 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400917 const XMLElement* element = node->ToElement();
918 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300919 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400920 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 }
922 }
923 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924}
925
926
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800927char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 // This is a recursive method, but thinking about it "at the current level"
930 // it is a pretty simple flat list:
931 // <foo/>
932 // <!-- comment -->
933 //
934 // With a special case:
935 // <foo>
936 // </foo>
937 // <!-- comment -->
938 //
939 // Where the closing element (/foo) *must* be the next thing after the opening
940 // element, and the names must match. BUT the tricky bit is that the closing
941 // element will be read by the child.
942 //
943 // 'endTag' is the end tag for this node, it is returned by a call to a child.
944 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800945
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 while( p && *p ) {
947 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800948
Lee Thomason624d43f2012-10-12 10:58:48 -0700949 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300950 if ( node == 0 ) {
951 break;
952 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 StrPair endTag;
955 p = node->ParseDeep( p, &endTag );
956 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400957 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700958 if ( !_document->Error() ) {
959 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 }
961 break;
962 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530964 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530965 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530966 // A declaration can only be the first child of a document.
967 // Set error, if document already has children.
968 if ( !_document->NoChildren() ) {
969 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
970 DeleteNode( decl );
971 break;
972 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530973 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530974
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400975 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500977 // We read the end tag. Return it to the parent.
978 if ( ele->ClosingType() == XMLElement::CLOSING ) {
979 if ( parentEnd ) {
980 ele->_value.TransferTo( parentEnd );
981 }
982 node->_memPool->SetTracked(); // created and then immediately deleted.
983 DeleteNode( node );
984 return p;
985 }
986
987 // Handle an end tag returned to this level.
988 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400989 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300990 if ( endTag.Empty() ) {
991 if ( ele->ClosingType() == XMLElement::OPEN ) {
992 mismatch = true;
993 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300995 else {
996 if ( ele->ClosingType() != XMLElement::OPEN ) {
997 mismatch = true;
998 }
Dmitry-Me886ad972015-07-22 11:00:51 +0300999 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001000 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 }
1002 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001003 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001004 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001005 DeleteNode( node );
1006 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001007 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 }
JayXondbfdd8f2014-12-12 20:07:14 -05001009 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 }
1011 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001012}
1013
Dmitry-Mee3225b12014-09-03 11:03:11 +04001014void XMLNode::DeleteNode( XMLNode* node )
1015{
1016 if ( node == 0 ) {
1017 return;
1018 }
1019 MemPool* pool = node->_memPool;
1020 node->~XMLNode();
1021 pool->Free( node );
1022}
1023
Lee Thomason3cebdc42015-01-05 17:16:28 -08001024void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001025{
1026 TIXMLASSERT( insertThis );
1027 TIXMLASSERT( insertThis->_document == _document );
1028
1029 if ( insertThis->_parent )
1030 insertThis->_parent->Unlink( insertThis );
1031 else
1032 insertThis->_memPool->SetTracked();
1033}
1034
Lee Thomason5492a1c2012-01-23 15:32:10 -08001035// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001036char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001037{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 const char* start = p;
1039 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 return p;
1045 }
1046 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1048 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001049 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001051
Lee Thomason624d43f2012-10-12 10:58:48 -07001052 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 if ( p && *p ) {
1054 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001055 }
1056 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001057 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 }
1059 }
1060 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001061}
1062
1063
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001067 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 }
1069 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1070 text->SetCData( this->CData() );
1071 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001072}
1073
1074
1075bool XMLText::ShallowEqual( const XMLNode* compare ) const
1076{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001077 const XMLText* text = compare->ToText();
1078 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001079}
1080
1081
Lee Thomason56bdd022012-02-09 18:16:58 -08001082bool XMLText::Accept( XMLVisitor* visitor ) const
1083{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001084 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001086}
1087
1088
Lee Thomason3f57d272012-01-11 15:30:03 -08001089// --------- XMLComment ---------- //
1090
Lee Thomasone4422302012-01-20 17:59:50 -08001091XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001092{
1093}
1094
1095
Lee Thomasonce0763e2012-01-11 15:43:54 -08001096XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001097{
Lee Thomason3f57d272012-01-11 15:30:03 -08001098}
1099
1100
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001101char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 // Comment parses as text.
1104 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 }
1109 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001110}
1111
1112
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001113XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001116 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 }
1118 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1119 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001120}
1121
1122
1123bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1124{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001125 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001126 const XMLComment* comment = compare->ToComment();
1127 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001128}
1129
1130
Lee Thomason751da522012-02-10 08:50:51 -08001131bool XMLComment::Accept( XMLVisitor* visitor ) const
1132{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001133 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001135}
Lee Thomason56bdd022012-02-09 18:16:58 -08001136
1137
Lee Thomason50f97b22012-02-11 16:33:40 -08001138// --------- XMLDeclaration ---------- //
1139
1140XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1141{
1142}
1143
1144
1145XMLDeclaration::~XMLDeclaration()
1146{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001148}
1149
1150
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001151char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 // Declaration parses as text.
1154 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 }
1159 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001160}
1161
1162
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001163XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 }
1168 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1169 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001170}
1171
1172
1173bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1174{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001175 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001176 const XMLDeclaration* declaration = compare->ToDeclaration();
1177 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001178}
1179
1180
1181
Lee Thomason50f97b22012-02-11 16:33:40 -08001182bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1183{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001184 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001186}
1187
1188// --------- XMLUnknown ---------- //
1189
1190XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1191{
1192}
1193
1194
1195XMLUnknown::~XMLUnknown()
1196{
1197}
1198
1199
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001200char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 // Unknown parses as text.
1203 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001204
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 }
1209 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001210}
1211
1212
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
1218 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1219 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001220}
1221
1222
1223bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1224{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001225 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001226 const XMLUnknown* unknown = compare->ToUnknown();
1227 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001228}
1229
1230
Lee Thomason50f97b22012-02-11 16:33:40 -08001231bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1232{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001233 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001235}
1236
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001237// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001238
1239const char* XMLAttribute::Name() const
1240{
1241 return _name.GetStr();
1242}
1243
1244const char* XMLAttribute::Value() const
1245{
1246 return _value.GetStr();
1247}
1248
Lee Thomason6f381b72012-03-02 12:59:39 -08001249char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001252 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 if ( !p || !*p ) {
1254 return 0;
1255 }
Lee Thomason22aead12012-01-23 13:29:35 -08001256
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 // Skip white space before =
1258 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001259 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 return 0;
1261 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001262
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 ++p; // move up to opening quote
1264 p = XMLUtil::SkipWhiteSpace( p );
1265 if ( *p != '\"' && *p != '\'' ) {
1266 return 0;
1267 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001268
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 char endTag[2] = { *p, 0 };
1270 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001271
Lee Thomason624d43f2012-10-12 10:58:48 -07001272 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001274}
1275
1276
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001277void XMLAttribute::SetName( const char* n )
1278{
Lee Thomason624d43f2012-10-12 10:58:48 -07001279 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001280}
1281
1282
Lee Thomason2fa81722012-11-09 12:37:46 -08001283XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 if ( XMLUtil::ToInt( Value(), value )) {
1286 return XML_NO_ERROR;
1287 }
1288 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001289}
1290
1291
Lee Thomason2fa81722012-11-09 12:37:46 -08001292XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 if ( XMLUtil::ToUnsigned( Value(), value )) {
1295 return XML_NO_ERROR;
1296 }
1297 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001298}
1299
1300
Lee Thomason2fa81722012-11-09 12:37:46 -08001301XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( XMLUtil::ToBool( Value(), value )) {
1304 return XML_NO_ERROR;
1305 }
1306 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001307}
1308
1309
Lee Thomason2fa81722012-11-09 12:37:46 -08001310XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( XMLUtil::ToFloat( Value(), value )) {
1313 return XML_NO_ERROR;
1314 }
1315 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001316}
1317
1318
Lee Thomason2fa81722012-11-09 12:37:46 -08001319XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 if ( XMLUtil::ToDouble( Value(), value )) {
1322 return XML_NO_ERROR;
1323 }
1324 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001325}
1326
1327
1328void XMLAttribute::SetAttribute( const char* v )
1329{
Lee Thomason624d43f2012-10-12 10:58:48 -07001330 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001331}
1332
1333
Lee Thomason1ff38e02012-02-14 18:18:16 -08001334void XMLAttribute::SetAttribute( int v )
1335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001338 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001339}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001340
1341
1342void XMLAttribute::SetAttribute( unsigned v )
1343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001346 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001347}
1348
1349
1350void XMLAttribute::SetAttribute( bool v )
1351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 char buf[BUF_SIZE];
1353 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001354 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001355}
1356
1357void XMLAttribute::SetAttribute( double v )
1358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 char buf[BUF_SIZE];
1360 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001361 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001362}
1363
1364void XMLAttribute::SetAttribute( float v )
1365{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 char buf[BUF_SIZE];
1367 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001368 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001369}
1370
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001371
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001372// --------- XMLElement ---------- //
1373XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001374 _closingType( 0 ),
1375 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001376{
1377}
1378
1379
1380XMLElement::~XMLElement()
1381{
Lee Thomason624d43f2012-10-12 10:58:48 -07001382 while( _rootAttribute ) {
1383 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001384 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001387}
1388
1389
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001390const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1391{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001392 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1394 return a;
1395 }
1396 }
1397 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001398}
1399
1400
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001401const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 const XMLAttribute* a = FindAttribute( name );
1404 if ( !a ) {
1405 return 0;
1406 }
1407 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1408 return a->Value();
1409 }
1410 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001411}
1412
1413
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001414const char* XMLElement::GetText() const
1415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001417 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001420}
1421
1422
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001423void XMLElement::SetText( const char* inText )
1424{
Uli Kusterer869bb592014-01-21 01:36:16 +01001425 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001426 FirstChild()->SetValue( inText );
1427 else {
1428 XMLText* theText = GetDocument()->NewText( inText );
1429 InsertFirstChild( theText );
1430 }
1431}
1432
Lee Thomason5bb2d802014-01-24 10:42:57 -08001433
1434void XMLElement::SetText( int v )
1435{
1436 char buf[BUF_SIZE];
1437 XMLUtil::ToStr( v, buf, BUF_SIZE );
1438 SetText( buf );
1439}
1440
1441
1442void XMLElement::SetText( unsigned v )
1443{
1444 char buf[BUF_SIZE];
1445 XMLUtil::ToStr( v, buf, BUF_SIZE );
1446 SetText( buf );
1447}
1448
1449
1450void XMLElement::SetText( bool v )
1451{
1452 char buf[BUF_SIZE];
1453 XMLUtil::ToStr( v, buf, BUF_SIZE );
1454 SetText( buf );
1455}
1456
1457
1458void XMLElement::SetText( float v )
1459{
1460 char buf[BUF_SIZE];
1461 XMLUtil::ToStr( v, buf, BUF_SIZE );
1462 SetText( buf );
1463}
1464
1465
1466void XMLElement::SetText( double v )
1467{
1468 char buf[BUF_SIZE];
1469 XMLUtil::ToStr( v, buf, BUF_SIZE );
1470 SetText( buf );
1471}
1472
1473
MortenMacFly4ee49f12013-01-14 20:03:14 +01001474XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001477 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001478 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return XML_SUCCESS;
1480 }
1481 return XML_CAN_NOT_CONVERT_TEXT;
1482 }
1483 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001484}
1485
1486
MortenMacFly4ee49f12013-01-14 20:03:14 +01001487XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001490 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001491 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 return XML_SUCCESS;
1493 }
1494 return XML_CAN_NOT_CONVERT_TEXT;
1495 }
1496 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001497}
1498
1499
MortenMacFly4ee49f12013-01-14 20:03:14 +01001500XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001503 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001504 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 return XML_SUCCESS;
1506 }
1507 return XML_CAN_NOT_CONVERT_TEXT;
1508 }
1509 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001510}
1511
1512
MortenMacFly4ee49f12013-01-14 20:03:14 +01001513XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001514{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001516 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001517 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 return XML_SUCCESS;
1519 }
1520 return XML_CAN_NOT_CONVERT_TEXT;
1521 }
1522 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001523}
1524
1525
MortenMacFly4ee49f12013-01-14 20:03:14 +01001526XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001529 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001530 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 return XML_SUCCESS;
1532 }
1533 return XML_CAN_NOT_CONVERT_TEXT;
1534 }
1535 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001536}
1537
1538
1539
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001540XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 XMLAttribute* last = 0;
1543 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1548 break;
1549 }
1550 }
1551 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001552 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1554 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 }
1558 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 }
1561 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001562 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 }
1564 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001565}
1566
1567
U-Stream\Leeae25a442012-02-17 17:48:16 -08001568void XMLElement::DeleteAttribute( const char* name )
1569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001571 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1573 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 }
1576 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001579 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 break;
1581 }
1582 prev = a;
1583 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001584}
1585
1586
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001587char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 const char* start = p;
1590 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 // Read the attributes.
1593 while( p ) {
1594 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001595 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001596 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 return 0;
1598 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001599
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001601 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001602 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1604 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001605 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001606
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001609 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 return 0;
1612 }
1613 // There is a minor bug here: if the attribute in the source xml
1614 // document is duplicated, it will not be detected and the
1615 // attribute will be doubly added. However, tracking the 'prevAttribute'
1616 // avoids re-scanning the attribute list. Preferring performance for
1617 // now, may reconsider in the future.
1618 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
1621 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 }
1624 prevAttribute = attrib;
1625 }
1626 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 else if ( *p == '>' ) {
1628 ++p;
1629 break;
1630 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001631 // end of the tag
1632 else if ( *p == '/' && *(p+1) == '>' ) {
1633 _closingType = CLOSED;
1634 return p+2; // done; sealed element.
1635 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001637 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 return 0;
1639 }
1640 }
1641 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001642}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001643
Dmitry-Mee3225b12014-09-03 11:03:11 +04001644void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1645{
1646 if ( attribute == 0 ) {
1647 return;
1648 }
1649 MemPool* pool = attribute->_memPool;
1650 attribute->~XMLAttribute();
1651 pool->Free( attribute );
1652}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001653
Lee Thomason67d61312012-01-24 16:01:51 -08001654//
1655// <ele></ele>
1656// <ele>foo<b>bar</b></ele>
1657//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001658char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001659{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 // Read the element name.
1661 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001662
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 // The closing element is the </element> form. It is
1664 // parsed just like a regular element then deleted from
1665 // the DOM.
1666 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 ++p;
1669 }
Lee Thomason67d61312012-01-24 16:01:51 -08001670
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 p = _value.ParseName( p );
1672 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 return 0;
1674 }
Lee Thomason67d61312012-01-24 16:01:51 -08001675
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 return p;
1679 }
Lee Thomason67d61312012-01-24 16:01:51 -08001680
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 p = XMLNode::ParseDeep( p, strPair );
1682 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001683}
1684
1685
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001686
1687XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1688{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001690 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 }
1692 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1693 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1694 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1695 }
1696 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001697}
1698
1699
1700bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1701{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001702 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001704 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001705
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 const XMLAttribute* a=FirstAttribute();
1707 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001708
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 while ( a && b ) {
1710 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1711 return false;
1712 }
1713 a = a->Next();
1714 b = b->Next();
1715 }
1716 if ( a || b ) {
1717 // different count
1718 return false;
1719 }
1720 return true;
1721 }
1722 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001723}
1724
1725
Lee Thomason751da522012-02-10 08:50:51 -08001726bool XMLElement::Accept( XMLVisitor* visitor ) const
1727{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001728 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1731 if ( !node->Accept( visitor ) ) {
1732 break;
1733 }
1734 }
1735 }
1736 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001737}
Lee Thomason56bdd022012-02-09 18:16:58 -08001738
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001739
Lee Thomason3f57d272012-01-11 15:30:03 -08001740// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001741
1742// Warning: List must match 'enum XMLError'
1743const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1744 "XML_SUCCESS",
1745 "XML_NO_ATTRIBUTE",
1746 "XML_WRONG_ATTRIBUTE_TYPE",
1747 "XML_ERROR_FILE_NOT_FOUND",
1748 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1749 "XML_ERROR_FILE_READ_ERROR",
1750 "XML_ERROR_ELEMENT_MISMATCH",
1751 "XML_ERROR_PARSING_ELEMENT",
1752 "XML_ERROR_PARSING_ATTRIBUTE",
1753 "XML_ERROR_IDENTIFYING_TAG",
1754 "XML_ERROR_PARSING_TEXT",
1755 "XML_ERROR_PARSING_CDATA",
1756 "XML_ERROR_PARSING_COMMENT",
1757 "XML_ERROR_PARSING_DECLARATION",
1758 "XML_ERROR_PARSING_UNKNOWN",
1759 "XML_ERROR_EMPTY_DOCUMENT",
1760 "XML_ERROR_MISMATCHED_ELEMENT",
1761 "XML_ERROR_PARSING",
1762 "XML_CAN_NOT_CONVERT_TEXT",
1763 "XML_NO_TEXT_NODE"
1764};
1765
1766
Lee Thomason624d43f2012-10-12 10:58:48 -07001767XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 _writeBOM( false ),
1770 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001771 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 _whitespace( whitespace ),
1773 _errorStr1( 0 ),
1774 _errorStr2( 0 ),
1775 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001776{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001777 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1778 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001779}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001780
1781
Lee Thomason3f57d272012-01-11 15:30:03 -08001782XMLDocument::~XMLDocument()
1783{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001784 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001785}
1786
1787
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001788void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001789{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001790 DeleteChildren();
1791
Dmitry-Meab37df82014-11-28 12:08:36 +03001792#ifdef DEBUG
1793 const bool hadError = Error();
1794#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _errorID = XML_NO_ERROR;
1796 _errorStr1 = 0;
1797 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001798
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 delete [] _charBuffer;
1800 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001801
1802#if 0
1803 _textPool.Trace( "text" );
1804 _elementPool.Trace( "element" );
1805 _commentPool.Trace( "comment" );
1806 _attributePool.Trace( "attribute" );
1807#endif
1808
1809#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001810 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001811 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1812 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1813 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1814 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1815 }
1816#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001817}
1818
Lee Thomason3f57d272012-01-11 15:30:03 -08001819
Lee Thomason2c85a712012-01-31 08:24:24 -08001820XMLElement* XMLDocument::NewElement( const char* name )
1821{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001822 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1824 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 ele->SetName( name );
1826 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001827}
1828
1829
Lee Thomason1ff38e02012-02-14 18:18:16 -08001830XMLComment* XMLDocument::NewComment( const char* str )
1831{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001832 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1834 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 comment->SetValue( str );
1836 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001837}
1838
1839
1840XMLText* XMLDocument::NewText( const char* str )
1841{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001842 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1844 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 text->SetValue( str );
1846 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001847}
1848
1849
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001850XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1851{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001852 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1854 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1856 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001857}
1858
1859
1860XMLUnknown* XMLDocument::NewUnknown( const char* str )
1861{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001862 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1864 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 unk->SetValue( str );
1866 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001867}
1868
Dmitry-Me01578db2014-08-19 10:18:48 +04001869static FILE* callfopen( const char* filepath, const char* mode )
1870{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001871 TIXMLASSERT( filepath );
1872 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001873#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1874 FILE* fp = 0;
1875 errno_t err = fopen_s( &fp, filepath, mode );
1876 if ( err ) {
1877 return 0;
1878 }
1879#else
1880 FILE* fp = fopen( filepath, mode );
1881#endif
1882 return fp;
1883}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001884
1885void XMLDocument::DeleteNode( XMLNode* node ) {
1886 TIXMLASSERT( node );
1887 TIXMLASSERT(node->_document == this );
1888 if (node->_parent) {
1889 node->_parent->DeleteChild( node );
1890 }
1891 else {
1892 // Isn't in the tree.
1893 // Use the parent delete.
1894 // Also, we need to mark it tracked: we 'know'
1895 // it was never used.
1896 node->_memPool->SetTracked();
1897 // Call the static XMLNode version:
1898 XMLNode::DeleteNode(node);
1899 }
1900}
1901
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001902
Lee Thomason2fa81722012-11-09 12:37:46 -08001903XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001904{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001905 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001906 FILE* fp = callfopen( filename, "rb" );
1907 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 }
1911 LoadFile( fp );
1912 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001914}
1915
1916
Lee Thomason2fa81722012-11-09 12:37:46 -08001917XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001918{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001919 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001920
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001921 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001922 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001923 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1924 return _errorID;
1925 }
1926
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001928 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001930 if ( filelength == -1L ) {
1931 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1932 return _errorID;
1933 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001934
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001935 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001936 // Cannot handle files which won't fit in buffer together with null terminator
1937 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1938 return _errorID;
1939 }
1940
Dmitry-Me72801b82015-05-07 09:41:39 +03001941 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001942 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001945
Dmitry-Me72801b82015-05-07 09:41:39 +03001946 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 _charBuffer = new char[size+1];
1948 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 if ( read != size ) {
1950 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001953
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955
Dmitry-Me97476b72015-01-01 16:15:57 +03001956 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001957 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001958}
1959
1960
Lee Thomason2fa81722012-11-09 12:37:46 -08001961XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001962{
Dmitry-Me01578db2014-08-19 10:18:48 +04001963 FILE* fp = callfopen( filename, "w" );
1964 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
1968 SaveFile(fp, compact);
1969 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001971}
1972
1973
Lee Thomason2fa81722012-11-09 12:37:46 -08001974XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001975{
Ant Mitchell189198f2015-03-24 16:20:36 +00001976 // Clear any error from the last save, otherwise it will get reported
1977 // for *this* call.
1978 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 XMLPrinter stream( fp, compact );
1980 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001982}
1983
Lee Thomason1ff38e02012-02-14 18:18:16 -08001984
Lee Thomason2fa81722012-11-09 12:37:46 -08001985XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001986{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001987 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001988
Lee Thomason82d32002014-02-21 22:47:18 -08001989 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 }
1993 if ( len == (size_t)(-1) ) {
1994 len = strlen( p );
1995 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001996 _charBuffer = new char[ len+1 ];
1997 memcpy( _charBuffer, p, len );
1998 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001999
Dmitry-Me97476b72015-01-01 16:15:57 +03002000 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002001 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002002 // clean up now essentially dangling memory.
2003 // and the parse fail can put objects in the
2004 // pools that are dead and inaccessible.
2005 DeleteChildren();
2006 _elementPool.Clear();
2007 _attributePool.Clear();
2008 _textPool.Clear();
2009 _commentPool.Clear();
2010 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002012}
2013
2014
PKEuS1c5f99e2013-07-06 11:28:39 +02002015void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002016{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002017 if ( streamer ) {
2018 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002020 else {
2021 XMLPrinter stdoutStreamer( stdout );
2022 Accept( &stdoutStreamer );
2023 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002024}
2025
2026
Lee Thomason2fa81722012-11-09 12:37:46 -08002027void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002028{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002029 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 _errorID = error;
2031 _errorStr1 = str1;
2032 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002033}
2034
Lee Thomason331596e2014-09-11 14:56:43 -07002035const char* XMLDocument::ErrorName() const
2036{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002037 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002038 const char* errorName = _errorNames[_errorID];
2039 TIXMLASSERT( errorName && errorName[0] );
2040 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002041}
Lee Thomason5cae8972012-01-24 18:03:07 -08002042
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002043void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002044{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002045 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 static const int LEN = 20;
2047 char buf1[LEN] = { 0 };
2048 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002049
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 if ( _errorStr1 ) {
2051 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 if ( _errorStr2 ) {
2054 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002056
Dmitry-Me2ad43202015-04-16 12:18:58 +03002057 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2058 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2059 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002060 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002061 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002063}
2064
Dmitry-Me97476b72015-01-01 16:15:57 +03002065void XMLDocument::Parse()
2066{
2067 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2068 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002069 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002070 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002071 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002072 if ( !*p ) {
2073 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2074 return;
2075 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002076 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002077}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002078
PKEuS1bfb9542013-08-04 13:51:17 +02002079XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 _elementJustOpened( false ),
2081 _firstElement( true ),
2082 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002083 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 _textDepth( -1 ),
2085 _processEntities( true ),
2086 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 _entityFlag[i] = false;
2090 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 }
2092 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002093 const char entityValue = entities[i].value;
2094 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2095 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002097 _restrictedEntityFlag[(unsigned char)'&'] = true;
2098 _restrictedEntityFlag[(unsigned char)'<'] = true;
2099 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002100 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002101}
2102
2103
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002104void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002105{
2106 va_list va;
2107 va_start( va, format );
2108
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 if ( _fp ) {
2110 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 }
2112 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002113 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 // Close out and re-start the va-args
2115 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002116 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002118 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002119 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002120 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002122 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002123}
2124
2125
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002126void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 for( int i=0; i<depth; ++i ) {
2129 Print( " " );
2130 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002131}
2132
2133
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002134void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 // Look for runs of bytes between entities to print.
2137 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002138
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002140 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002142 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 // Remember, char is sometimes signed. (How many times has that bitten me?)
2144 if ( *q > 0 && *q < ENTITY_RANGE ) {
2145 // Check for entities. If one is found, flush
2146 // the stream up until the entity, write the
2147 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002148 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002150 const size_t delta = q - p;
2151 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002152 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002153 Print( "%.*s", toPrint, p );
2154 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002156 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 for( int i=0; i<NUM_ENTITIES; ++i ) {
2158 if ( entities[i].value == *q ) {
2159 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002160 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 break;
2162 }
2163 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002164 if ( !entityPatternPrinted ) {
2165 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2166 TIXMLASSERT( false );
2167 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 ++p;
2169 }
2170 }
2171 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002172 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 }
2174 }
2175 // Flush the remaining string. This will be the entire
2176 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002177 TIXMLASSERT( p <= q );
2178 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 Print( "%s", p );
2180 }
Lee Thomason857b8682012-01-25 17:50:25 -08002181}
2182
U-Stream\Leeae25a442012-02-17 17:48:16 -08002183
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002184void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002187 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 -07002188 Print( "%s", bom );
2189 }
2190 if ( writeDec ) {
2191 PushDeclaration( "xml version=\"1.0\"" );
2192 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002193}
2194
2195
Uli Kusterer593a33d2014-02-01 12:48:51 +01002196void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002197{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002198 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002200
Uli Kusterer593a33d2014-02-01 12:48:51 +01002201 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002203 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002204 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002207
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002209 _elementJustOpened = true;
2210 _firstElement = false;
2211 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002212}
2213
2214
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002215void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002216{
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 Print( " %s=\"", name );
2219 PrintString( value, false );
2220 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002221}
2222
2223
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002224void XMLPrinter::PushAttribute( const char* name, int v )
2225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 char buf[BUF_SIZE];
2227 XMLUtil::ToStr( v, buf, BUF_SIZE );
2228 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002229}
2230
2231
2232void XMLPrinter::PushAttribute( const char* name, unsigned v )
2233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 char buf[BUF_SIZE];
2235 XMLUtil::ToStr( v, buf, BUF_SIZE );
2236 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002237}
2238
2239
2240void XMLPrinter::PushAttribute( const char* name, bool v )
2241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 char buf[BUF_SIZE];
2243 XMLUtil::ToStr( v, buf, BUF_SIZE );
2244 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002245}
2246
2247
2248void XMLPrinter::PushAttribute( const char* name, double v )
2249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 char buf[BUF_SIZE];
2251 XMLUtil::ToStr( v, buf, BUF_SIZE );
2252 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002253}
2254
2255
Uli Kustererca412e82014-02-01 13:35:05 +01002256void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002257{
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 --_depth;
2259 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002260
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "/>" );
2263 }
2264 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002265 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002267 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 }
2269 Print( "</%s>", name );
2270 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002271
Lee Thomason624d43f2012-10-12 10:58:48 -07002272 if ( _textDepth == _depth ) {
2273 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 }
Uli Kustererca412e82014-02-01 13:35:05 +01002275 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 Print( "\n" );
2277 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002278 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002279}
2280
2281
Dmitry-Mea092bc12014-12-23 17:57:05 +03002282void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002283{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002284 if ( !_elementJustOpened ) {
2285 return;
2286 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002289}
2290
2291
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002292void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002293{
Lee Thomason624d43f2012-10-12 10:58:48 -07002294 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002295
Dmitry-Mea092bc12014-12-23 17:57:05 +03002296 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002298 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
2300 else {
2301 PrintString( text, true );
2302 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002303}
2304
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002305void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 char buf[BUF_SIZE];
2308 XMLUtil::ToStr( value, buf, BUF_SIZE );
2309 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002310}
2311
2312
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002313void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 char buf[BUF_SIZE];
2316 XMLUtil::ToStr( value, buf, BUF_SIZE );
2317 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002318}
2319
2320
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002321void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002322{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 char buf[BUF_SIZE];
2324 XMLUtil::ToStr( value, buf, BUF_SIZE );
2325 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002326}
2327
2328
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002329void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 char buf[BUF_SIZE];
2332 XMLUtil::ToStr( value, buf, BUF_SIZE );
2333 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002334}
2335
2336
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002337void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 char buf[BUF_SIZE];
2340 XMLUtil::ToStr( value, buf, BUF_SIZE );
2341 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002342}
2343
Lee Thomason5cae8972012-01-24 18:03:07 -08002344
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002345void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002346{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002347 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002348 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002350 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002352 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002354}
Lee Thomason751da522012-02-10 08:50:51 -08002355
2356
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002357void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002358{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002359 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002362 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002364 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002366}
2367
2368
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002369void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002370{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002371 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002378}
2379
2380
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002381bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002382{
Lee Thomason624d43f2012-10-12 10:58:48 -07002383 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 if ( doc.HasBOM() ) {
2385 PushHeader( true, false );
2386 }
2387 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002388}
2389
2390
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002391bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002392{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002393 const XMLElement* parentElem = 0;
2394 if ( element.Parent() ) {
2395 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002396 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002397 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002398 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002399 while ( attribute ) {
2400 PushAttribute( attribute->Name(), attribute->Value() );
2401 attribute = attribute->Next();
2402 }
2403 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002404}
2405
2406
Uli Kustererca412e82014-02-01 13:35:05 +01002407bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002408{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002409 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002411}
2412
2413
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002414bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002416 PushText( text.Value(), text.CData() );
2417 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002418}
2419
2420
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002421bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 PushComment( comment.Value() );
2424 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002425}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002426
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002427bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002429 PushDeclaration( declaration.Value() );
2430 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002431}
2432
2433
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002434bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 PushUnknown( unknown.Value() );
2437 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002438}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002439
Lee Thomason685b8952012-11-12 13:00:06 -08002440} // namespace tinyxml2
2441