blob: 3f45d1a8b428624d588291de963d18f2857e9efd [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>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomason53db4a62015-06-11 22:52:08 -070033#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030034 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070035 /*int _snprintf_s(
36 char *buffer,
37 size_t sizeOfBuffer,
38 size_t count,
39 const char *format [,
40 argument] ...
41 );*/
42 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
43 {
44 va_list va;
45 va_start( va, format );
46 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
47 va_end( va );
48 return result;
49 }
50
51 inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
52 {
53 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
54 return result;
55 }
56
57 #define TIXML_VSCPRINTF _vscprintf
58 #define TIXML_SSCANF sscanf_s
59#elif defined _MSC_VER
60 // Microsoft Visual Studio 2003 and earlier or WinCE
61 #define TIXML_SNPRINTF _snprintf
62 #define TIXML_VSNPRINTF _vsnprintf
63 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070064 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070065 // Microsoft Visual Studio 2003 and not WinCE.
66 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
67 #else
68 // Microsoft Visual Studio 2003 and earlier or WinCE.
69 inline int TIXML_VSCPRINTF( const char* format, va_list va )
70 {
71 int len = 512;
72 for (;;) {
73 len = len*2;
74 char* str = new char[len]();
75 const int required = _vsnprintf(str, len, format, va);
76 delete[] str;
77 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030078 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070079 len = required;
80 break;
81 }
82 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030083 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070084 return len;
85 }
86 #endif
87#else
88 // GCC version 3 and higher
89 //#warning( "Using sn* functions." )
90 #define TIXML_SNPRINTF snprintf
91 #define TIXML_VSNPRINTF vsnprintf
92 inline int TIXML_VSCPRINTF( const char* format, va_list va )
93 {
94 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030095 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070096 return len;
97 }
98 #define TIXML_SSCANF sscanf
99#endif
100
101
Lee Thomasone4422302012-01-20 17:59:50 -0800102static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800103static const char LF = LINE_FEED;
104static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
105static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800106static const char SINGLE_QUOTE = '\'';
107static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800108
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800109// Bunch of unicode info at:
110// http://www.unicode.org/faq/utf_bom.html
111// ef bb bf (Microsoft "lead bytes") - designates UTF-8
112
113static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
114static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
115static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800116
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800117namespace tinyxml2
118{
119
Lee Thomason8ee79892012-01-25 17:44:30 -0800120struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700121 const char* pattern;
122 int length;
123 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800124};
125
126static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700127static const Entity entities[NUM_ENTITIES] = {
128 { "quot", 4, DOUBLE_QUOTE },
129 { "amp", 3, '&' },
130 { "apos", 4, SINGLE_QUOTE },
131 { "lt", 2, '<' },
132 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800133};
134
Lee Thomasonfde6a752012-01-14 18:08:12 -0800135
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136StrPair::~StrPair()
137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700138 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800139}
140
141
Lee Thomason29658802014-11-27 22:31:11 -0800142void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300143{
Lee Thomason29658802014-11-27 22:31:11 -0800144 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145 return;
146 }
147 // This in effect implements the assignment operator by "moving"
148 // ownership (as in auto_ptr).
149
Lee Thomason29658802014-11-27 22:31:11 -0800150 TIXMLASSERT( other->_flags == 0 );
151 TIXMLASSERT( other->_start == 0 );
152 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300153
Lee Thomason29658802014-11-27 22:31:11 -0800154 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300155
Lee Thomason29658802014-11-27 22:31:11 -0800156 other->_flags = _flags;
157 other->_start = _start;
158 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300159
160 _flags = 0;
161 _start = 0;
162 _end = 0;
163}
164
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800165void StrPair::Reset()
166{
Lee Thomason120b3a62012-10-12 10:06:59 -0700167 if ( _flags & NEEDS_DELETE ) {
168 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 _flags = 0;
171 _start = 0;
172 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800173}
174
175
176void StrPair::SetStr( const char* str, int flags )
177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700178 Reset();
179 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 _start = new char[ len+1 ];
181 memcpy( _start, str, len+1 );
182 _end = _start + len;
183 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800184}
185
186
187char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700189 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400191 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700192 char endChar = *endTag;
193 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 // Inner loop of text parsing.
196 while ( *p ) {
197 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
198 Set( start, p, strFlags );
199 return p + length;
200 }
201 ++p;
202 }
203 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800204}
205
206
207char* StrPair::ParseName( char* p )
208{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400209 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 return 0;
211 }
JayXonee525db2014-12-24 04:01:42 -0500212 if ( !XMLUtil::IsNameStartChar( *p ) ) {
213 return 0;
214 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400216 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500217 ++p;
218 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700219 ++p;
220 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800221
JayXonee525db2014-12-24 04:01:42 -0500222 Set( start, p, 0 );
223 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800224}
225
226
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700227void StrPair::CollapseWhitespace()
228{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400229 // Adjusting _start would cause undefined behavior on delete[]
230 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700232 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700233
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300234 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700235 char* p = _start; // the read pointer
236 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700238 while( *p ) {
239 if ( XMLUtil::IsWhiteSpace( *p )) {
240 p = XMLUtil::SkipWhiteSpace( p );
241 if ( *p == 0 ) {
242 break; // don't write to q; this trims the trailing space.
243 }
244 *q = ' ';
245 ++q;
246 }
247 *q = *p;
248 ++q;
249 ++p;
250 }
251 *q = 0;
252 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700253}
254
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800255
Lee Thomasone4422302012-01-20 17:59:50 -0800256const char* StrPair::GetStr()
257{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300258 TIXMLASSERT( _start );
259 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700260 if ( _flags & NEEDS_FLUSH ) {
261 *_end = 0;
262 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 if ( _flags ) {
265 char* p = _start; // the read pointer
266 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800267
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 while( p < _end ) {
269 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700270 // CR-LF pair becomes LF
271 // CR alone becomes LF
272 // LF-CR becomes LF
273 if ( *(p+1) == LF ) {
274 p += 2;
275 }
276 else {
277 ++p;
278 }
279 *q++ = LF;
280 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700281 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700282 if ( *(p+1) == CR ) {
283 p += 2;
284 }
285 else {
286 ++p;
287 }
288 *q++ = LF;
289 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700290 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 // Entities handled by tinyXML2:
292 // - special entities in the entity table [in/out]
293 // - numeric character reference [in]
294 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800295
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700296 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400297 const int buflen = 10;
298 char buf[buflen] = { 0 };
299 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300300 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
301 if ( adjusted == 0 ) {
302 *q = *p;
303 ++p;
304 ++q;
305 }
306 else {
307 TIXMLASSERT( 0 <= len && len <= buflen );
308 TIXMLASSERT( q + len <= adjusted );
309 p = adjusted;
310 memcpy( q, buf, len );
311 q += len;
312 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
314 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300315 bool entityFound = false;
316 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400317 const Entity& entity = entities[i];
318 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
319 && *( p + entity.length + 1 ) == ';' ) {
320 // Found an entity - convert.
321 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400323 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300324 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 break;
326 }
327 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 // fixme: treat as error?
330 ++p;
331 ++q;
332 }
333 }
334 }
335 else {
336 *q = *p;
337 ++p;
338 ++q;
339 }
340 }
341 *q = 0;
342 }
343 // The loop below has plenty going on, and this
344 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300345 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 CollapseWhitespace();
347 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700348 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300350 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700351 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800352}
353
Lee Thomason2c85a712012-01-31 08:24:24 -0800354
Lee Thomasone4422302012-01-20 17:59:50 -0800355
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800356
Lee Thomason56bdd022012-02-09 18:16:58 -0800357// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800358
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800359const char* XMLUtil::ReadBOM( const char* p, bool* bom )
360{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300361 TIXMLASSERT( p );
362 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 *bom = false;
364 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
365 // Check for BOM:
366 if ( *(pu+0) == TIXML_UTF_LEAD_0
367 && *(pu+1) == TIXML_UTF_LEAD_1
368 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
369 *bom = true;
370 p += 3;
371 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300372 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800374}
375
376
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800377void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const unsigned long BYTE_MASK = 0xBF;
380 const unsigned long BYTE_MARK = 0x80;
381 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 if (input < 0x80) {
384 *length = 1;
385 }
386 else if ( input < 0x800 ) {
387 *length = 2;
388 }
389 else if ( input < 0x10000 ) {
390 *length = 3;
391 }
392 else if ( input < 0x200000 ) {
393 *length = 4;
394 }
395 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300396 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 return;
398 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800401
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 // Scary scary fall throughs.
403 switch (*length) {
404 case 4:
405 --output;
406 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
407 input >>= 6;
408 case 3:
409 --output;
410 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
411 input >>= 6;
412 case 2:
413 --output;
414 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
415 input >>= 6;
416 case 1:
417 --output;
418 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100419 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300420 default:
421 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800423}
424
425
426const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 // Presume an entity, and pull it out.
429 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800430
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 if ( *(p+1) == '#' && *(p+2) ) {
432 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300433 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 ptrdiff_t delta = 0;
435 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800436 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800437
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( *(p+2) == 'x' ) {
439 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300440 const char* q = p+3;
441 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 return 0;
443 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800444
Lee Thomason7e67bc82015-01-12 14:05:12 -0800445 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800446
Dmitry-Me9f56e122015-01-12 10:07:54 +0300447 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700448 return 0;
449 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800450 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 delta = q-p;
453 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800454
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700456 unsigned int digit = 0;
457
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300459 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 }
461 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300462 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 }
464 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300465 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 }
467 else {
468 return 0;
469 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300470 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
472 const unsigned int digitScaled = mult * digit;
473 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
474 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300475 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700476 mult *= 16;
477 --q;
478 }
479 }
480 else {
481 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300482 const char* q = p+2;
483 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 return 0;
485 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800486
Lee Thomason7e67bc82015-01-12 14:05:12 -0800487 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800488
Dmitry-Me9f56e122015-01-12 10:07:54 +0300489 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 return 0;
491 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800492 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 delta = q-p;
495 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 while ( *q != '#' ) {
498 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300499 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300500 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 }
506 else {
507 return 0;
508 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300509 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 mult *= 10;
511 --q;
512 }
513 }
514 // convert the UCS to UTF-8
515 ConvertUTF32ToUTF8( ucs, value, length );
516 return p + delta + 1;
517 }
518 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800519}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800520
521
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700522void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700525}
526
527
528void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700531}
532
533
534void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700537}
538
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800539/*
540 ToStr() of a number is a very tricky topic.
541 https://github.com/leethomason/tinyxml2/issues/106
542*/
Lee Thomason21be8822012-07-15 17:27:22 -0700543void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
544{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800545 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700546}
547
548
549void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
550{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800551 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700552}
553
554
555bool XMLUtil::ToInt( const char* str, int* value )
556{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
558 return true;
559 }
560 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
566 return true;
567 }
568 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700569}
570
571bool XMLUtil::ToBool( const char* str, bool* value )
572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 int ival = 0;
574 if ( ToInt( str, &ival )) {
575 *value = (ival==0) ? false : true;
576 return true;
577 }
578 if ( StringEqual( str, "true" ) ) {
579 *value = true;
580 return true;
581 }
582 else if ( StringEqual( str, "false" ) ) {
583 *value = false;
584 return true;
585 }
586 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700587}
588
589
590bool XMLUtil::ToFloat( const char* str, float* value )
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
593 return true;
594 }
595 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700596}
597
598bool XMLUtil::ToDouble( const char* str, double* value )
599{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700600 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
601 return true;
602 }
603 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700604}
605
606
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700607char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800608{
Dmitry-Me02384662015-03-03 16:02:13 +0300609 TIXMLASSERT( node );
610 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400611 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700612 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300613 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300614 *node = 0;
615 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 return p;
617 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800618
Dmitry-Me962083b2015-05-26 11:38:30 +0300619 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 static const char* xmlHeader = { "<?" };
621 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300623 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800625
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 static const int xmlHeaderLen = 2;
627 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300629 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800631
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
633 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400634 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300636 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
638 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 p += xmlHeaderLen;
640 }
641 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300642 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 returnNode = new (_commentPool.Alloc()) XMLComment( this );
644 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 p += commentHeaderLen;
646 }
647 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300648 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 p += cdataHeaderLen;
653 text->SetCData( true );
654 }
655 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300656 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
658 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 p += dtdHeaderLen;
660 }
661 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300662 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 returnNode = new (_elementPool.Alloc()) XMLElement( this );
664 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 p += elementHeaderLen;
666 }
667 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 returnNode = new (_textPool.Alloc()) XMLText( this );
670 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 p = start; // Back it up, all the text counts.
672 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673
Dmitry-Me02384662015-03-03 16:02:13 +0300674 TIXMLASSERT( returnNode );
675 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 *node = returnNode;
677 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678}
679
680
Lee Thomason751da522012-02-10 08:50:51 -0800681bool XMLDocument::Accept( XMLVisitor* visitor ) const
682{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300683 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 if ( visitor->VisitEnter( *this ) ) {
685 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
686 if ( !node->Accept( visitor ) ) {
687 break;
688 }
689 }
690 }
691 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800692}
Lee Thomason56bdd022012-02-09 18:16:58 -0800693
694
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695// --------- XMLNode ----------- //
696
697XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700698 _document( doc ),
699 _parent( 0 ),
700 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200701 _prev( 0 ), _next( 0 ),
702 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800704}
705
706
707XMLNode::~XMLNode()
708{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 if ( _parent ) {
711 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800713}
714
Michael Daumling21626882013-10-22 17:03:37 +0200715const char* XMLNode::Value() const
716{
Lee Thomason85492022015-05-22 11:07:45 -0700717 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530718 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530719 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200720 return _value.GetStr();
721}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800722
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800723void XMLNode::SetValue( const char* str, bool staticMem )
724{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
728 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800731}
732
733
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800734void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800735{
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300737 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300738 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700741
Dmitry-Mee3225b12014-09-03 11:03:11 +0400742 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700744 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800745}
746
747
748void XMLNode::Unlink( XMLNode* child )
749{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300750 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300751 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300752 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 if ( child == _firstChild ) {
754 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 if ( child == _lastChild ) {
757 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 }
Lee Thomasond923c672012-01-23 08:44:25 -0800759
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 if ( child->_prev ) {
761 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 if ( child->_next ) {
764 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700766 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800767}
768
769
U-Stream\Leeae25a442012-02-17 17:48:16 -0800770void XMLNode::DeleteChild( XMLNode* node )
771{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300772 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300773 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400775 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800776}
777
778
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800779XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
780{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300781 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300782 if ( addThis->_document != _document ) {
783 TIXMLASSERT( false );
784 return 0;
785 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800786 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700787
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( _lastChild ) {
789 TIXMLASSERT( _firstChild );
790 TIXMLASSERT( _lastChild->_next == 0 );
791 _lastChild->_next = addThis;
792 addThis->_prev = _lastChild;
793 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800794
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 }
797 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 TIXMLASSERT( _firstChild == 0 );
799 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800800
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 addThis->_prev = 0;
802 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700804 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800806}
807
808
Lee Thomason1ff38e02012-02-14 18:18:16 -0800809XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
810{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300811 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300812 if ( addThis->_document != _document ) {
813 TIXMLASSERT( false );
814 return 0;
815 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800816 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700817
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 if ( _firstChild ) {
819 TIXMLASSERT( _lastChild );
820 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800821
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 _firstChild->_prev = addThis;
823 addThis->_next = _firstChild;
824 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800825
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
828 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 TIXMLASSERT( _lastChild == 0 );
830 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800831
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 addThis->_prev = 0;
833 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700835 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400836 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800837}
838
839
840XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
841{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300842 TIXMLASSERT( addThis );
843 if ( addThis->_document != _document ) {
844 TIXMLASSERT( false );
845 return 0;
846 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700847
Dmitry-Meabb2d042014-12-09 12:59:31 +0300848 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 return 0;
853 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800854
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 // The last node or the only node.
857 return InsertEndChild( addThis );
858 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800859 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 addThis->_prev = afterThis;
861 addThis->_next = afterThis->_next;
862 afterThis->_next->_prev = addThis;
863 afterThis->_next = addThis;
864 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800866}
867
868
869
870
Dmitry-Me886ad972015-07-22 11:00:51 +0300871const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800872{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300873 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
874 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300876 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 return element;
878 }
879 }
880 }
881 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800882}
883
884
Dmitry-Me886ad972015-07-22 11:00:51 +0300885const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800886{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300887 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
888 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300890 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return element;
892 }
893 }
894 }
895 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800896}
897
898
Dmitry-Me886ad972015-07-22 11:00:51 +0300899const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800900{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300901 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400902 const XMLElement* element = node->ToElement();
903 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300904 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400905 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
907 }
908 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909}
910
911
Dmitry-Me886ad972015-07-22 11:00:51 +0300912const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800913{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300914 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400915 const XMLElement* element = node->ToElement();
916 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300917 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400918 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 }
920 }
921 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922}
923
924
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800925char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800926{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 // This is a recursive method, but thinking about it "at the current level"
928 // it is a pretty simple flat list:
929 // <foo/>
930 // <!-- comment -->
931 //
932 // With a special case:
933 // <foo>
934 // </foo>
935 // <!-- comment -->
936 //
937 // Where the closing element (/foo) *must* be the next thing after the opening
938 // element, and the names must match. BUT the tricky bit is that the closing
939 // element will be read by the child.
940 //
941 // 'endTag' is the end tag for this node, it is returned by a call to a child.
942 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800943
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 while( p && *p ) {
945 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800946
Lee Thomason624d43f2012-10-12 10:58:48 -0700947 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300948 if ( node == 0 ) {
949 break;
950 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800951
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 StrPair endTag;
953 p = node->ParseDeep( p, &endTag );
954 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400955 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700956 if ( !_document->Error() ) {
957 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 break;
960 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800961
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530962 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530963 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530964 // A declaration can only be the first child of a document.
965 // Set error, if document already has children.
966 if ( !_document->NoChildren() ) {
967 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
968 DeleteNode( decl );
969 break;
970 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530971 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530972
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400973 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500975 // We read the end tag. Return it to the parent.
976 if ( ele->ClosingType() == XMLElement::CLOSING ) {
977 if ( parentEnd ) {
978 ele->_value.TransferTo( parentEnd );
979 }
980 node->_memPool->SetTracked(); // created and then immediately deleted.
981 DeleteNode( node );
982 return p;
983 }
984
985 // Handle an end tag returned to this level.
986 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400987 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300988 if ( endTag.Empty() ) {
989 if ( ele->ClosingType() == XMLElement::OPEN ) {
990 mismatch = true;
991 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300993 else {
994 if ( ele->ClosingType() != XMLElement::OPEN ) {
995 mismatch = true;
996 }
Dmitry-Me886ad972015-07-22 11:00:51 +0300997 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400998 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001001 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001002 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001003 DeleteNode( node );
1004 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001005 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 }
JayXondbfdd8f2014-12-12 20:07:14 -05001007 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 }
1009 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001010}
1011
Dmitry-Mee3225b12014-09-03 11:03:11 +04001012void XMLNode::DeleteNode( XMLNode* node )
1013{
1014 if ( node == 0 ) {
1015 return;
1016 }
1017 MemPool* pool = node->_memPool;
1018 node->~XMLNode();
1019 pool->Free( node );
1020}
1021
Lee Thomason3cebdc42015-01-05 17:16:28 -08001022void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001023{
1024 TIXMLASSERT( insertThis );
1025 TIXMLASSERT( insertThis->_document == _document );
1026
1027 if ( insertThis->_parent )
1028 insertThis->_parent->Unlink( insertThis );
1029 else
1030 insertThis->_memPool->SetTracked();
1031}
1032
Lee Thomason5492a1c2012-01-23 15:32:10 -08001033// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001034char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 const char* start = p;
1037 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 return p;
1043 }
1044 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1046 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001047 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001049
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 if ( p && *p ) {
1052 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001053 }
1054 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001055 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 }
1057 }
1058 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001059}
1060
1061
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001062XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1063{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001065 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1068 text->SetCData( this->CData() );
1069 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070}
1071
1072
1073bool XMLText::ShallowEqual( const XMLNode* compare ) const
1074{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001075 const XMLText* text = compare->ToText();
1076 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001077}
1078
1079
Lee Thomason56bdd022012-02-09 18:16:58 -08001080bool XMLText::Accept( XMLVisitor* visitor ) const
1081{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001082 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001084}
1085
1086
Lee Thomason3f57d272012-01-11 15:30:03 -08001087// --------- XMLComment ---------- //
1088
Lee Thomasone4422302012-01-20 17:59:50 -08001089XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001090{
1091}
1092
1093
Lee Thomasonce0763e2012-01-11 15:43:54 -08001094XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001095{
Lee Thomason3f57d272012-01-11 15:30:03 -08001096}
1097
1098
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001099char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 // Comment parses as text.
1102 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001103 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 }
1107 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001108}
1109
1110
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001111XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001114 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 }
1116 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1117 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001118}
1119
1120
1121bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1122{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001123 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001124 const XMLComment* comment = compare->ToComment();
1125 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001126}
1127
1128
Lee Thomason751da522012-02-10 08:50:51 -08001129bool XMLComment::Accept( XMLVisitor* visitor ) const
1130{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001131 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001133}
Lee Thomason56bdd022012-02-09 18:16:58 -08001134
1135
Lee Thomason50f97b22012-02-11 16:33:40 -08001136// --------- XMLDeclaration ---------- //
1137
1138XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1139{
1140}
1141
1142
1143XMLDeclaration::~XMLDeclaration()
1144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001146}
1147
1148
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001149char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 // Declaration parses as text.
1152 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 }
1157 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001158}
1159
1160
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001161XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 }
1166 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1167 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
1171bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1172{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001173 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001174 const XMLDeclaration* declaration = compare->ToDeclaration();
1175 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001176}
1177
1178
1179
Lee Thomason50f97b22012-02-11 16:33:40 -08001180bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1181{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001182 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001184}
1185
1186// --------- XMLUnknown ---------- //
1187
1188XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1189{
1190}
1191
1192
1193XMLUnknown::~XMLUnknown()
1194{
1195}
1196
1197
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001198char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 // Unknown parses as text.
1201 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001202
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 }
1207 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001208}
1209
1210
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001211XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
1216 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1217 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001218}
1219
1220
1221bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1222{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001223 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001224 const XMLUnknown* unknown = compare->ToUnknown();
1225 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001226}
1227
1228
Lee Thomason50f97b22012-02-11 16:33:40 -08001229bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1230{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001231 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001233}
1234
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001235// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001236
1237const char* XMLAttribute::Name() const
1238{
1239 return _name.GetStr();
1240}
1241
1242const char* XMLAttribute::Value() const
1243{
1244 return _value.GetStr();
1245}
1246
Lee Thomason6f381b72012-03-02 12:59:39 -08001247char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 if ( !p || !*p ) {
1252 return 0;
1253 }
Lee Thomason22aead12012-01-23 13:29:35 -08001254
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 // Skip white space before =
1256 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001257 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 return 0;
1259 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001260
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 ++p; // move up to opening quote
1262 p = XMLUtil::SkipWhiteSpace( p );
1263 if ( *p != '\"' && *p != '\'' ) {
1264 return 0;
1265 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001266
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 char endTag[2] = { *p, 0 };
1268 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001269
Lee Thomason624d43f2012-10-12 10:58:48 -07001270 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001272}
1273
1274
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001275void XMLAttribute::SetName( const char* n )
1276{
Lee Thomason624d43f2012-10-12 10:58:48 -07001277 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001278}
1279
1280
Lee Thomason2fa81722012-11-09 12:37:46 -08001281XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 if ( XMLUtil::ToInt( Value(), value )) {
1284 return XML_NO_ERROR;
1285 }
1286 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001287}
1288
1289
Lee Thomason2fa81722012-11-09 12:37:46 -08001290XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 if ( XMLUtil::ToUnsigned( Value(), value )) {
1293 return XML_NO_ERROR;
1294 }
1295 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001296}
1297
1298
Lee Thomason2fa81722012-11-09 12:37:46 -08001299XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 if ( XMLUtil::ToBool( Value(), value )) {
1302 return XML_NO_ERROR;
1303 }
1304 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001305}
1306
1307
Lee Thomason2fa81722012-11-09 12:37:46 -08001308XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 if ( XMLUtil::ToFloat( Value(), value )) {
1311 return XML_NO_ERROR;
1312 }
1313 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001314}
1315
1316
Lee Thomason2fa81722012-11-09 12:37:46 -08001317XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( XMLUtil::ToDouble( Value(), value )) {
1320 return XML_NO_ERROR;
1321 }
1322 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001323}
1324
1325
1326void XMLAttribute::SetAttribute( const char* v )
1327{
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001329}
1330
1331
Lee Thomason1ff38e02012-02-14 18:18:16 -08001332void XMLAttribute::SetAttribute( int v )
1333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001336 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001337}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001338
1339
1340void XMLAttribute::SetAttribute( unsigned v )
1341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001344 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001345}
1346
1347
1348void XMLAttribute::SetAttribute( bool v )
1349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 char buf[BUF_SIZE];
1351 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001352 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001353}
1354
1355void XMLAttribute::SetAttribute( double v )
1356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 char buf[BUF_SIZE];
1358 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001360}
1361
1362void XMLAttribute::SetAttribute( float v )
1363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 char buf[BUF_SIZE];
1365 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001366 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001367}
1368
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001369
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001370// --------- XMLElement ---------- //
1371XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 _closingType( 0 ),
1373 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001374{
1375}
1376
1377
1378XMLElement::~XMLElement()
1379{
Lee Thomason624d43f2012-10-12 10:58:48 -07001380 while( _rootAttribute ) {
1381 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001382 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001383 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001385}
1386
1387
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001388const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1389{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001390 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1392 return a;
1393 }
1394 }
1395 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001396}
1397
1398
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001399const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 const XMLAttribute* a = FindAttribute( name );
1402 if ( !a ) {
1403 return 0;
1404 }
1405 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1406 return a->Value();
1407 }
1408 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001409}
1410
1411
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001412const char* XMLElement::GetText() const
1413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001415 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001418}
1419
1420
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001421void XMLElement::SetText( const char* inText )
1422{
Uli Kusterer869bb592014-01-21 01:36:16 +01001423 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001424 FirstChild()->SetValue( inText );
1425 else {
1426 XMLText* theText = GetDocument()->NewText( inText );
1427 InsertFirstChild( theText );
1428 }
1429}
1430
Lee Thomason5bb2d802014-01-24 10:42:57 -08001431
1432void XMLElement::SetText( int v )
1433{
1434 char buf[BUF_SIZE];
1435 XMLUtil::ToStr( v, buf, BUF_SIZE );
1436 SetText( buf );
1437}
1438
1439
1440void XMLElement::SetText( unsigned v )
1441{
1442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
1444 SetText( buf );
1445}
1446
1447
1448void XMLElement::SetText( bool v )
1449{
1450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
1452 SetText( buf );
1453}
1454
1455
1456void XMLElement::SetText( float v )
1457{
1458 char buf[BUF_SIZE];
1459 XMLUtil::ToStr( v, buf, BUF_SIZE );
1460 SetText( buf );
1461}
1462
1463
1464void XMLElement::SetText( double v )
1465{
1466 char buf[BUF_SIZE];
1467 XMLUtil::ToStr( v, buf, BUF_SIZE );
1468 SetText( buf );
1469}
1470
1471
MortenMacFly4ee49f12013-01-14 20:03:14 +01001472XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001475 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001476 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 return XML_SUCCESS;
1478 }
1479 return XML_CAN_NOT_CONVERT_TEXT;
1480 }
1481 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001482}
1483
1484
MortenMacFly4ee49f12013-01-14 20:03:14 +01001485XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001488 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001489 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 return XML_SUCCESS;
1491 }
1492 return XML_CAN_NOT_CONVERT_TEXT;
1493 }
1494 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001495}
1496
1497
MortenMacFly4ee49f12013-01-14 20:03:14 +01001498XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001501 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001502 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return XML_SUCCESS;
1504 }
1505 return XML_CAN_NOT_CONVERT_TEXT;
1506 }
1507 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001508}
1509
1510
MortenMacFly4ee49f12013-01-14 20:03:14 +01001511XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001512{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001514 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001515 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 return XML_SUCCESS;
1517 }
1518 return XML_CAN_NOT_CONVERT_TEXT;
1519 }
1520 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001521}
1522
1523
MortenMacFly4ee49f12013-01-14 20:03:14 +01001524XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001527 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001528 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 return XML_SUCCESS;
1530 }
1531 return XML_CAN_NOT_CONVERT_TEXT;
1532 }
1533 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001534}
1535
1536
1537
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001538XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 XMLAttribute* last = 0;
1541 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001542 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1546 break;
1547 }
1548 }
1549 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001550 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001551 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1552 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 }
1556 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001557 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 }
1559 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001560 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 }
1562 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001563}
1564
1565
U-Stream\Leeae25a442012-02-17 17:48:16 -08001566void XMLElement::DeleteAttribute( const char* name )
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1571 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 }
1574 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001577 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 break;
1579 }
1580 prev = a;
1581 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001582}
1583
1584
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001585char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 const char* start = p;
1588 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001589
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 // Read the attributes.
1591 while( p ) {
1592 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001593 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 return 0;
1596 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001597
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001599 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001600 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001601 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1602 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001603 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001604
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001607 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 return 0;
1610 }
1611 // There is a minor bug here: if the attribute in the source xml
1612 // document is duplicated, it will not be detected and the
1613 // attribute will be doubly added. However, tracking the 'prevAttribute'
1614 // avoids re-scanning the attribute list. Preferring performance for
1615 // now, may reconsider in the future.
1616 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 prevAttribute = attrib;
1623 }
1624 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 else if ( *p == '>' ) {
1626 ++p;
1627 break;
1628 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001629 // end of the tag
1630 else if ( *p == '/' && *(p+1) == '>' ) {
1631 _closingType = CLOSED;
1632 return p+2; // done; sealed element.
1633 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 return 0;
1637 }
1638 }
1639 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001640}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001641
Dmitry-Mee3225b12014-09-03 11:03:11 +04001642void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1643{
1644 if ( attribute == 0 ) {
1645 return;
1646 }
1647 MemPool* pool = attribute->_memPool;
1648 attribute->~XMLAttribute();
1649 pool->Free( attribute );
1650}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001651
Lee Thomason67d61312012-01-24 16:01:51 -08001652//
1653// <ele></ele>
1654// <ele>foo<b>bar</b></ele>
1655//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001656char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001657{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 // Read the element name.
1659 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001660
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 // The closing element is the </element> form. It is
1662 // parsed just like a regular element then deleted from
1663 // the DOM.
1664 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001665 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 ++p;
1667 }
Lee Thomason67d61312012-01-24 16:01:51 -08001668
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 p = _value.ParseName( p );
1670 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 return 0;
1672 }
Lee Thomason67d61312012-01-24 16:01:51 -08001673
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 return p;
1677 }
Lee Thomason67d61312012-01-24 16:01:51 -08001678
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 p = XMLNode::ParseDeep( p, strPair );
1680 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001681}
1682
1683
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001684
1685XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1686{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 }
1690 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1691 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1692 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1693 }
1694 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001695}
1696
1697
1698bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1699{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001700 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001702 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001703
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 const XMLAttribute* a=FirstAttribute();
1705 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001706
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 while ( a && b ) {
1708 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1709 return false;
1710 }
1711 a = a->Next();
1712 b = b->Next();
1713 }
1714 if ( a || b ) {
1715 // different count
1716 return false;
1717 }
1718 return true;
1719 }
1720 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001721}
1722
1723
Lee Thomason751da522012-02-10 08:50:51 -08001724bool XMLElement::Accept( XMLVisitor* visitor ) const
1725{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001726 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1729 if ( !node->Accept( visitor ) ) {
1730 break;
1731 }
1732 }
1733 }
1734 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001735}
Lee Thomason56bdd022012-02-09 18:16:58 -08001736
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001737
Lee Thomason3f57d272012-01-11 15:30:03 -08001738// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001739
1740// Warning: List must match 'enum XMLError'
1741const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1742 "XML_SUCCESS",
1743 "XML_NO_ATTRIBUTE",
1744 "XML_WRONG_ATTRIBUTE_TYPE",
1745 "XML_ERROR_FILE_NOT_FOUND",
1746 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1747 "XML_ERROR_FILE_READ_ERROR",
1748 "XML_ERROR_ELEMENT_MISMATCH",
1749 "XML_ERROR_PARSING_ELEMENT",
1750 "XML_ERROR_PARSING_ATTRIBUTE",
1751 "XML_ERROR_IDENTIFYING_TAG",
1752 "XML_ERROR_PARSING_TEXT",
1753 "XML_ERROR_PARSING_CDATA",
1754 "XML_ERROR_PARSING_COMMENT",
1755 "XML_ERROR_PARSING_DECLARATION",
1756 "XML_ERROR_PARSING_UNKNOWN",
1757 "XML_ERROR_EMPTY_DOCUMENT",
1758 "XML_ERROR_MISMATCHED_ELEMENT",
1759 "XML_ERROR_PARSING",
1760 "XML_CAN_NOT_CONVERT_TEXT",
1761 "XML_NO_TEXT_NODE"
1762};
1763
1764
Lee Thomason624d43f2012-10-12 10:58:48 -07001765XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 _writeBOM( false ),
1768 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001769 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 _whitespace( whitespace ),
1771 _errorStr1( 0 ),
1772 _errorStr2( 0 ),
1773 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001774{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001775 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1776 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001777}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001778
1779
Lee Thomason3f57d272012-01-11 15:30:03 -08001780XMLDocument::~XMLDocument()
1781{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001782 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001783}
1784
1785
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001786void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001787{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001788 DeleteChildren();
1789
Dmitry-Meab37df82014-11-28 12:08:36 +03001790#ifdef DEBUG
1791 const bool hadError = Error();
1792#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 _errorID = XML_NO_ERROR;
1794 _errorStr1 = 0;
1795 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001796
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 delete [] _charBuffer;
1798 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001799
1800#if 0
1801 _textPool.Trace( "text" );
1802 _elementPool.Trace( "element" );
1803 _commentPool.Trace( "comment" );
1804 _attributePool.Trace( "attribute" );
1805#endif
1806
1807#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001808 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001809 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1810 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1811 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1812 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1813 }
1814#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001815}
1816
Lee Thomason3f57d272012-01-11 15:30:03 -08001817
Lee Thomason2c85a712012-01-31 08:24:24 -08001818XMLElement* XMLDocument::NewElement( const char* name )
1819{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001820 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1822 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 ele->SetName( name );
1824 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001825}
1826
1827
Lee Thomason1ff38e02012-02-14 18:18:16 -08001828XMLComment* XMLDocument::NewComment( const char* str )
1829{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001830 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1832 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 comment->SetValue( str );
1834 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001835}
1836
1837
1838XMLText* XMLDocument::NewText( const char* str )
1839{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001840 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1842 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 text->SetValue( str );
1844 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001845}
1846
1847
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001848XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1849{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001850 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1852 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1854 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001855}
1856
1857
1858XMLUnknown* XMLDocument::NewUnknown( const char* str )
1859{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001860 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1862 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 unk->SetValue( str );
1864 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001865}
1866
Dmitry-Me01578db2014-08-19 10:18:48 +04001867static FILE* callfopen( const char* filepath, const char* mode )
1868{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001869 TIXMLASSERT( filepath );
1870 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001871#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1872 FILE* fp = 0;
1873 errno_t err = fopen_s( &fp, filepath, mode );
1874 if ( err ) {
1875 return 0;
1876 }
1877#else
1878 FILE* fp = fopen( filepath, mode );
1879#endif
1880 return fp;
1881}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001882
1883void XMLDocument::DeleteNode( XMLNode* node ) {
1884 TIXMLASSERT( node );
1885 TIXMLASSERT(node->_document == this );
1886 if (node->_parent) {
1887 node->_parent->DeleteChild( node );
1888 }
1889 else {
1890 // Isn't in the tree.
1891 // Use the parent delete.
1892 // Also, we need to mark it tracked: we 'know'
1893 // it was never used.
1894 node->_memPool->SetTracked();
1895 // Call the static XMLNode version:
1896 XMLNode::DeleteNode(node);
1897 }
1898}
1899
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001900
Lee Thomason2fa81722012-11-09 12:37:46 -08001901XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001902{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001903 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001904 FILE* fp = callfopen( filename, "rb" );
1905 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 }
1909 LoadFile( fp );
1910 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912}
1913
1914
Lee Thomason2fa81722012-11-09 12:37:46 -08001915XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001916{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001917 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001918
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001919 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001920 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001921 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1922 return _errorID;
1923 }
1924
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001926 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001928 if ( filelength == -1L ) {
1929 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1930 return _errorID;
1931 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001932
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001933 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001934 // Cannot handle files which won't fit in buffer together with null terminator
1935 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1936 return _errorID;
1937 }
1938
Dmitry-Me72801b82015-05-07 09:41:39 +03001939 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001940 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001942 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001943
Dmitry-Me72801b82015-05-07 09:41:39 +03001944 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 _charBuffer = new char[size+1];
1946 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 if ( read != size ) {
1948 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001951
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001953
Dmitry-Me97476b72015-01-01 16:15:57 +03001954 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001956}
1957
1958
Lee Thomason2fa81722012-11-09 12:37:46 -08001959XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001960{
Dmitry-Me01578db2014-08-19 10:18:48 +04001961 FILE* fp = callfopen( filename, "w" );
1962 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 }
1966 SaveFile(fp, compact);
1967 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001969}
1970
1971
Lee Thomason2fa81722012-11-09 12:37:46 -08001972XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001973{
Ant Mitchell189198f2015-03-24 16:20:36 +00001974 // Clear any error from the last save, otherwise it will get reported
1975 // for *this* call.
1976 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 XMLPrinter stream( fp, compact );
1978 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001980}
1981
Lee Thomason1ff38e02012-02-14 18:18:16 -08001982
Lee Thomason2fa81722012-11-09 12:37:46 -08001983XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001984{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001985 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001986
Lee Thomason82d32002014-02-21 22:47:18 -08001987 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
1991 if ( len == (size_t)(-1) ) {
1992 len = strlen( p );
1993 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001994 _charBuffer = new char[ len+1 ];
1995 memcpy( _charBuffer, p, len );
1996 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001997
Dmitry-Me97476b72015-01-01 16:15:57 +03001998 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001999 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002000 // clean up now essentially dangling memory.
2001 // and the parse fail can put objects in the
2002 // pools that are dead and inaccessible.
2003 DeleteChildren();
2004 _elementPool.Clear();
2005 _attributePool.Clear();
2006 _textPool.Clear();
2007 _commentPool.Clear();
2008 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002009 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002010}
2011
2012
PKEuS1c5f99e2013-07-06 11:28:39 +02002013void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002014{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002015 if ( streamer ) {
2016 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002018 else {
2019 XMLPrinter stdoutStreamer( stdout );
2020 Accept( &stdoutStreamer );
2021 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002022}
2023
2024
Lee Thomason2fa81722012-11-09 12:37:46 -08002025void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002026{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002027 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 _errorID = error;
2029 _errorStr1 = str1;
2030 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002031}
2032
Lee Thomason331596e2014-09-11 14:56:43 -07002033const char* XMLDocument::ErrorName() const
2034{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002035 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002036 const char* errorName = _errorNames[_errorID];
2037 TIXMLASSERT( errorName && errorName[0] );
2038 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002039}
Lee Thomason5cae8972012-01-24 18:03:07 -08002040
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002041void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002042{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002043 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 static const int LEN = 20;
2045 char buf1[LEN] = { 0 };
2046 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002047
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _errorStr1 ) {
2049 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 if ( _errorStr2 ) {
2052 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002054
Dmitry-Me2ad43202015-04-16 12:18:58 +03002055 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2056 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2057 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002058 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002059 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002061}
2062
Dmitry-Me97476b72015-01-01 16:15:57 +03002063void XMLDocument::Parse()
2064{
2065 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2066 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002067 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002068 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002069 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002070 if ( !*p ) {
2071 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2072 return;
2073 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002074 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002075}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002076
PKEuS1bfb9542013-08-04 13:51:17 +02002077XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _elementJustOpened( false ),
2079 _firstElement( true ),
2080 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002081 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 _textDepth( -1 ),
2083 _processEntities( true ),
2084 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 _entityFlag[i] = false;
2088 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 }
2090 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002091 const char entityValue = entities[i].value;
2092 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2093 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002095 _restrictedEntityFlag[(unsigned char)'&'] = true;
2096 _restrictedEntityFlag[(unsigned char)'<'] = true;
2097 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002098 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002099}
2100
2101
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002102void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002103{
2104 va_list va;
2105 va_start( va, format );
2106
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 if ( _fp ) {
2108 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 }
2110 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002111 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 // Close out and re-start the va-args
2113 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002114 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002116 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002117 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002118 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002120 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002121}
2122
2123
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002124void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 for( int i=0; i<depth; ++i ) {
2127 Print( " " );
2128 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002129}
2130
2131
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002132void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 // Look for runs of bytes between entities to print.
2135 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002136
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002138 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002140 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 // Remember, char is sometimes signed. (How many times has that bitten me?)
2142 if ( *q > 0 && *q < ENTITY_RANGE ) {
2143 // Check for entities. If one is found, flush
2144 // the stream up until the entity, write the
2145 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002146 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002148 const size_t delta = q - p;
2149 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002150 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002151 Print( "%.*s", toPrint, p );
2152 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002154 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 for( int i=0; i<NUM_ENTITIES; ++i ) {
2156 if ( entities[i].value == *q ) {
2157 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002158 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 break;
2160 }
2161 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002162 if ( !entityPatternPrinted ) {
2163 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2164 TIXMLASSERT( false );
2165 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 ++p;
2167 }
2168 }
2169 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002170 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 }
2172 }
2173 // Flush the remaining string. This will be the entire
2174 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002175 TIXMLASSERT( p <= q );
2176 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 Print( "%s", p );
2178 }
Lee Thomason857b8682012-01-25 17:50:25 -08002179}
2180
U-Stream\Leeae25a442012-02-17 17:48:16 -08002181
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002182void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002185 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 -07002186 Print( "%s", bom );
2187 }
2188 if ( writeDec ) {
2189 PushDeclaration( "xml version=\"1.0\"" );
2190 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002191}
2192
2193
Uli Kusterer593a33d2014-02-01 12:48:51 +01002194void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002195{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002196 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002198
Uli Kusterer593a33d2014-02-01 12:48:51 +01002199 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002201 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002202 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002205
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 _elementJustOpened = true;
2208 _firstElement = false;
2209 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002210}
2211
2212
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002213void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002214{
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 Print( " %s=\"", name );
2217 PrintString( value, false );
2218 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002219}
2220
2221
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002222void XMLPrinter::PushAttribute( const char* name, int v )
2223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 char buf[BUF_SIZE];
2225 XMLUtil::ToStr( v, buf, BUF_SIZE );
2226 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002227}
2228
2229
2230void XMLPrinter::PushAttribute( const char* name, unsigned v )
2231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 char buf[BUF_SIZE];
2233 XMLUtil::ToStr( v, buf, BUF_SIZE );
2234 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002235}
2236
2237
2238void XMLPrinter::PushAttribute( const char* name, bool v )
2239{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 char buf[BUF_SIZE];
2241 XMLUtil::ToStr( v, buf, BUF_SIZE );
2242 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002243}
2244
2245
2246void XMLPrinter::PushAttribute( const char* name, double v )
2247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 char buf[BUF_SIZE];
2249 XMLUtil::ToStr( v, buf, BUF_SIZE );
2250 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002251}
2252
2253
Uli Kustererca412e82014-02-01 13:35:05 +01002254void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002255{
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 --_depth;
2257 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002258
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "/>" );
2261 }
2262 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002263 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 }
2267 Print( "</%s>", name );
2268 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002269
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 if ( _textDepth == _depth ) {
2271 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 }
Uli Kustererca412e82014-02-01 13:35:05 +01002273 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 Print( "\n" );
2275 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002276 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002277}
2278
2279
Dmitry-Mea092bc12014-12-23 17:57:05 +03002280void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002281{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002282 if ( !_elementJustOpened ) {
2283 return;
2284 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002287}
2288
2289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002291{
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002293
Dmitry-Mea092bc12014-12-23 17:57:05 +03002294 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002296 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 }
2298 else {
2299 PrintString( text, true );
2300 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002301}
2302
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002303void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 char buf[BUF_SIZE];
2306 XMLUtil::ToStr( value, buf, BUF_SIZE );
2307 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002308}
2309
2310
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002311void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 char buf[BUF_SIZE];
2314 XMLUtil::ToStr( value, buf, BUF_SIZE );
2315 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002316}
2317
2318
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002319void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002321 char buf[BUF_SIZE];
2322 XMLUtil::ToStr( value, buf, BUF_SIZE );
2323 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002324}
2325
2326
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002327void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 char buf[BUF_SIZE];
2330 XMLUtil::ToStr( value, buf, BUF_SIZE );
2331 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002332}
2333
2334
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002335void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 char buf[BUF_SIZE];
2338 XMLUtil::ToStr( value, buf, BUF_SIZE );
2339 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002340}
2341
Lee Thomason5cae8972012-01-24 18:03:07 -08002342
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002343void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002344{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002345 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002346 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002348 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002350 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002352}
Lee Thomason751da522012-02-10 08:50:51 -08002353
2354
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002355void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002356{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002357 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002362 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002364}
2365
2366
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002367void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002368{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002369 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002376}
2377
2378
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002379bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002380{
Lee Thomason624d43f2012-10-12 10:58:48 -07002381 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 if ( doc.HasBOM() ) {
2383 PushHeader( true, false );
2384 }
2385 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002386}
2387
2388
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002389bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002390{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002391 const XMLElement* parentElem = 0;
2392 if ( element.Parent() ) {
2393 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002394 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002395 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002396 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 while ( attribute ) {
2398 PushAttribute( attribute->Name(), attribute->Value() );
2399 attribute = attribute->Next();
2400 }
2401 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002402}
2403
2404
Uli Kustererca412e82014-02-01 13:35:05 +01002405bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002406{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002407 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002409}
2410
2411
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002412bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 PushText( text.Value(), text.CData() );
2415 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002416}
2417
2418
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002419bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 PushComment( comment.Value() );
2422 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002423}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002424
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002425bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 PushDeclaration( declaration.Value() );
2428 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002429}
2430
2431
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002432bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002433{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002434 PushUnknown( unknown.Value() );
2435 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002436}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002437
Lee Thomason685b8952012-11-12 13:00:06 -08002438} // namespace tinyxml2
2439