blob: edf714d545f70148ca990c4dec434a7bc14788a4 [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 ) {
78 len = required;
79 break;
80 }
81 }
82 return len;
83 }
84 #endif
85#else
86 // GCC version 3 and higher
87 //#warning( "Using sn* functions." )
88 #define TIXML_SNPRINTF snprintf
89 #define TIXML_VSNPRINTF vsnprintf
90 inline int TIXML_VSCPRINTF( const char* format, va_list va )
91 {
92 int len = vsnprintf( 0, 0, format, va );
93 return len;
94 }
95 #define TIXML_SSCANF sscanf
96#endif
97
98
Lee Thomasone4422302012-01-20 17:59:50 -080099static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800100static const char LF = LINE_FEED;
101static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
102static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800103static const char SINGLE_QUOTE = '\'';
104static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800106// Bunch of unicode info at:
107// http://www.unicode.org/faq/utf_bom.html
108// ef bb bf (Microsoft "lead bytes") - designates UTF-8
109
110static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
111static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
112static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800113
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800114namespace tinyxml2
115{
116
Lee Thomason8ee79892012-01-25 17:44:30 -0800117struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700118 const char* pattern;
119 int length;
120 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800121};
122
123static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700124static const Entity entities[NUM_ENTITIES] = {
125 { "quot", 4, DOUBLE_QUOTE },
126 { "amp", 3, '&' },
127 { "apos", 4, SINGLE_QUOTE },
128 { "lt", 2, '<' },
129 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800130};
131
Lee Thomasonfde6a752012-01-14 18:08:12 -0800132
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800133StrPair::~StrPair()
134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136}
137
138
Lee Thomason29658802014-11-27 22:31:11 -0800139void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300140{
Lee Thomason29658802014-11-27 22:31:11 -0800141 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300142 return;
143 }
144 // This in effect implements the assignment operator by "moving"
145 // ownership (as in auto_ptr).
146
Lee Thomason29658802014-11-27 22:31:11 -0800147 TIXMLASSERT( other->_flags == 0 );
148 TIXMLASSERT( other->_start == 0 );
149 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300150
Lee Thomason29658802014-11-27 22:31:11 -0800151 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300152
Lee Thomason29658802014-11-27 22:31:11 -0800153 other->_flags = _flags;
154 other->_start = _start;
155 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
157 _flags = 0;
158 _start = 0;
159 _end = 0;
160}
161
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800162void StrPair::Reset()
163{
Lee Thomason120b3a62012-10-12 10:06:59 -0700164 if ( _flags & NEEDS_DELETE ) {
165 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700166 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700167 _flags = 0;
168 _start = 0;
169 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800170}
171
172
173void StrPair::SetStr( const char* str, int flags )
174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700175 Reset();
176 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700177 _start = new char[ len+1 ];
178 memcpy( _start, str, len+1 );
179 _end = _start + len;
180 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800181}
182
183
184char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700186 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800187
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400188 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700189 char endChar = *endTag;
190 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800191
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700192 // Inner loop of text parsing.
193 while ( *p ) {
194 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
195 Set( start, p, strFlags );
196 return p + length;
197 }
198 ++p;
199 }
200 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201}
202
203
204char* StrPair::ParseName( char* p )
205{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400206 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700207 return 0;
208 }
JayXonee525db2014-12-24 04:01:42 -0500209 if ( !XMLUtil::IsNameStartChar( *p ) ) {
210 return 0;
211 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800212
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400213 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500214 ++p;
215 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 ++p;
217 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800218
JayXonee525db2014-12-24 04:01:42 -0500219 Set( start, p, 0 );
220 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800221}
222
223
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700224void StrPair::CollapseWhitespace()
225{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400226 // Adjusting _start would cause undefined behavior on delete[]
227 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700228 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700229 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700230
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300231 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700232 char* p = _start; // the read pointer
233 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700234
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700235 while( *p ) {
236 if ( XMLUtil::IsWhiteSpace( *p )) {
237 p = XMLUtil::SkipWhiteSpace( p );
238 if ( *p == 0 ) {
239 break; // don't write to q; this trims the trailing space.
240 }
241 *q = ' ';
242 ++q;
243 }
244 *q = *p;
245 ++q;
246 ++p;
247 }
248 *q = 0;
249 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700250}
251
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800252
Lee Thomasone4422302012-01-20 17:59:50 -0800253const char* StrPair::GetStr()
254{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300255 TIXMLASSERT( _start );
256 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 if ( _flags & NEEDS_FLUSH ) {
258 *_end = 0;
259 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800260
Lee Thomason120b3a62012-10-12 10:06:59 -0700261 if ( _flags ) {
262 char* p = _start; // the read pointer
263 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800264
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 while( p < _end ) {
266 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700267 // CR-LF pair becomes LF
268 // CR alone becomes LF
269 // LF-CR becomes LF
270 if ( *(p+1) == LF ) {
271 p += 2;
272 }
273 else {
274 ++p;
275 }
276 *q++ = LF;
277 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700279 if ( *(p+1) == CR ) {
280 p += 2;
281 }
282 else {
283 ++p;
284 }
285 *q++ = LF;
286 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700287 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 // Entities handled by tinyXML2:
289 // - special entities in the entity table [in/out]
290 // - numeric character reference [in]
291 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800292
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400294 const int buflen = 10;
295 char buf[buflen] = { 0 };
296 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300297 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
298 if ( adjusted == 0 ) {
299 *q = *p;
300 ++p;
301 ++q;
302 }
303 else {
304 TIXMLASSERT( 0 <= len && len <= buflen );
305 TIXMLASSERT( q + len <= adjusted );
306 p = adjusted;
307 memcpy( q, buf, len );
308 q += len;
309 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 }
311 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300312 bool entityFound = false;
313 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400314 const Entity& entity = entities[i];
315 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
316 && *( p + entity.length + 1 ) == ';' ) {
317 // Found an entity - convert.
318 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400320 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300321 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 break;
323 }
324 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300325 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 // fixme: treat as error?
327 ++p;
328 ++q;
329 }
330 }
331 }
332 else {
333 *q = *p;
334 ++p;
335 ++q;
336 }
337 }
338 *q = 0;
339 }
340 // The loop below has plenty going on, and this
341 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300342 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 CollapseWhitespace();
344 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700345 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300347 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700348 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800349}
350
Lee Thomason2c85a712012-01-31 08:24:24 -0800351
Lee Thomasone4422302012-01-20 17:59:50 -0800352
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800353
Lee Thomason56bdd022012-02-09 18:16:58 -0800354// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800355
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800356const char* XMLUtil::ReadBOM( const char* p, bool* bom )
357{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300358 TIXMLASSERT( p );
359 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 *bom = false;
361 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
362 // Check for BOM:
363 if ( *(pu+0) == TIXML_UTF_LEAD_0
364 && *(pu+1) == TIXML_UTF_LEAD_1
365 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
366 *bom = true;
367 p += 3;
368 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300369 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800371}
372
373
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 const unsigned long BYTE_MASK = 0xBF;
377 const unsigned long BYTE_MARK = 0x80;
378 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800379
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700380 if (input < 0x80) {
381 *length = 1;
382 }
383 else if ( input < 0x800 ) {
384 *length = 2;
385 }
386 else if ( input < 0x10000 ) {
387 *length = 3;
388 }
389 else if ( input < 0x200000 ) {
390 *length = 4;
391 }
392 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300393 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 return;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 // Scary scary fall throughs.
400 switch (*length) {
401 case 4:
402 --output;
403 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
404 input >>= 6;
405 case 3:
406 --output;
407 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
408 input >>= 6;
409 case 2:
410 --output;
411 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
412 input >>= 6;
413 case 1:
414 --output;
415 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100416 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300417 default:
418 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800420}
421
422
423const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 // Presume an entity, and pull it out.
426 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 if ( *(p+1) == '#' && *(p+2) ) {
429 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300430 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 ptrdiff_t delta = 0;
432 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800433 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800434
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 if ( *(p+2) == 'x' ) {
436 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300437 const char* q = p+3;
438 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 return 0;
440 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800441
Lee Thomason7e67bc82015-01-12 14:05:12 -0800442 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800443
Dmitry-Me9f56e122015-01-12 10:07:54 +0300444 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 return 0;
446 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800447 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700449 delta = q-p;
450 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700453 unsigned int digit = 0;
454
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300456 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 }
458 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300459 digit = *q - 'a' + 10;
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 {
465 return 0;
466 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300467 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300468 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
469 const unsigned int digitScaled = mult * digit;
470 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
471 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300472 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 mult *= 16;
474 --q;
475 }
476 }
477 else {
478 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300479 const char* q = p+2;
480 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 return 0;
482 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800483
Lee Thomason7e67bc82015-01-12 14:05:12 -0800484 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800485
Dmitry-Me9f56e122015-01-12 10:07:54 +0300486 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 return 0;
488 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800489 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800490
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 delta = q-p;
492 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 while ( *q != '#' ) {
495 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300497 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300498 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
499 const unsigned int digitScaled = mult * digit;
500 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
501 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 }
503 else {
504 return 0;
505 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300506 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 mult *= 10;
508 --q;
509 }
510 }
511 // convert the UCS to UTF-8
512 ConvertUTF32ToUTF8( ucs, value, length );
513 return p + delta + 1;
514 }
515 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800517
518
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700519void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700522}
523
524
525void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
526{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700528}
529
530
531void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800536/*
537 ToStr() of a number is a very tricky topic.
538 https://github.com/leethomason/tinyxml2/issues/106
539*/
Lee Thomason21be8822012-07-15 17:27:22 -0700540void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
541{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800542 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700543}
544
545
546void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
547{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800548 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700549}
550
551
552bool XMLUtil::ToInt( const char* str, int* value )
553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
555 return true;
556 }
557 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700558}
559
560bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
561{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
563 return true;
564 }
565 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700566}
567
568bool XMLUtil::ToBool( const char* str, bool* value )
569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 int ival = 0;
571 if ( ToInt( str, &ival )) {
572 *value = (ival==0) ? false : true;
573 return true;
574 }
575 if ( StringEqual( str, "true" ) ) {
576 *value = true;
577 return true;
578 }
579 else if ( StringEqual( str, "false" ) ) {
580 *value = false;
581 return true;
582 }
583 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700584}
585
586
587bool XMLUtil::ToFloat( const char* str, float* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToDouble( const char* str, double* value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700604char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605{
Dmitry-Me02384662015-03-03 16:02:13 +0300606 TIXMLASSERT( node );
607 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400608 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300610 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300611 *node = 0;
612 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 return p;
614 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800615
Dmitry-Me962083b2015-05-26 11:38:30 +0300616 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 static const char* xmlHeader = { "<?" };
618 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300620 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 static const int xmlHeaderLen = 2;
624 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300626 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800628
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
630 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400631 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300633 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
635 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 p += xmlHeaderLen;
637 }
638 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300639 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 returnNode = new (_commentPool.Alloc()) XMLComment( this );
641 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 p += commentHeaderLen;
643 }
644 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300645 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 p += cdataHeaderLen;
650 text->SetCData( true );
651 }
652 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300653 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
655 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 p += dtdHeaderLen;
657 }
658 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300659 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 returnNode = new (_elementPool.Alloc()) XMLElement( this );
661 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 p += elementHeaderLen;
663 }
664 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300665 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 returnNode = new (_textPool.Alloc()) XMLText( this );
667 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 p = start; // Back it up, all the text counts.
669 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Dmitry-Me02384662015-03-03 16:02:13 +0300671 TIXMLASSERT( returnNode );
672 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 *node = returnNode;
674 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675}
676
677
Lee Thomason751da522012-02-10 08:50:51 -0800678bool XMLDocument::Accept( XMLVisitor* visitor ) const
679{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300680 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 if ( visitor->VisitEnter( *this ) ) {
682 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
683 if ( !node->Accept( visitor ) ) {
684 break;
685 }
686 }
687 }
688 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800689}
Lee Thomason56bdd022012-02-09 18:16:58 -0800690
691
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692// --------- XMLNode ----------- //
693
694XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 _document( doc ),
696 _parent( 0 ),
697 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200698 _prev( 0 ), _next( 0 ),
699 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800700{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701}
702
703
704XMLNode::~XMLNode()
705{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( _parent ) {
708 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800710}
711
Michael Daumling21626882013-10-22 17:03:37 +0200712const char* XMLNode::Value() const
713{
Lee Thomason85492022015-05-22 11:07:45 -0700714 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530715 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530716 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200717 return _value.GetStr();
718}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800719
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800720void XMLNode::SetValue( const char* str, bool staticMem )
721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800728}
729
730
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800731void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800732{
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300734 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300735 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700738
Dmitry-Mee3225b12014-09-03 11:03:11 +0400739 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800742}
743
744
745void XMLNode::Unlink( XMLNode* child )
746{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300747 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300749 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 if ( child == _firstChild ) {
751 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 if ( child == _lastChild ) {
754 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
Lee Thomasond923c672012-01-23 08:44:25 -0800756
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( child->_prev ) {
758 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 if ( child->_next ) {
761 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700763 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800764}
765
766
U-Stream\Leeae25a442012-02-17 17:48:16 -0800767void XMLNode::DeleteChild( XMLNode* node )
768{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300769 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300770 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400772 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800773}
774
775
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800776XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
777{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300778 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300779 if ( addThis->_document != _document ) {
780 TIXMLASSERT( false );
781 return 0;
782 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800783 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( _lastChild ) {
786 TIXMLASSERT( _firstChild );
787 TIXMLASSERT( _lastChild->_next == 0 );
788 _lastChild->_next = addThis;
789 addThis->_prev = _lastChild;
790 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800791
Lee Thomason624d43f2012-10-12 10:58:48 -0700792 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
794 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 TIXMLASSERT( _firstChild == 0 );
796 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 addThis->_prev = 0;
799 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800803}
804
805
Lee Thomason1ff38e02012-02-14 18:18:16 -0800806XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
807{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300808 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300809 if ( addThis->_document != _document ) {
810 TIXMLASSERT( false );
811 return 0;
812 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800813 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700814
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 if ( _firstChild ) {
816 TIXMLASSERT( _lastChild );
817 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800818
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 _firstChild->_prev = addThis;
820 addThis->_next = _firstChild;
821 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 }
825 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 TIXMLASSERT( _lastChild == 0 );
827 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800828
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 addThis->_prev = 0;
830 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400833 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800834}
835
836
837XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
838{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300839 TIXMLASSERT( addThis );
840 if ( addThis->_document != _document ) {
841 TIXMLASSERT( false );
842 return 0;
843 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700844
Dmitry-Meabb2d042014-12-09 12:59:31 +0300845 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300848 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 return 0;
850 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 // The last node or the only node.
854 return InsertEndChild( addThis );
855 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800856 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_prev = afterThis;
858 addThis->_next = afterThis->_next;
859 afterThis->_next->_prev = addThis;
860 afterThis->_next = addThis;
861 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866
867
Dmitry-Me886ad972015-07-22 11:00:51 +0300868const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800869{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300870 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
871 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300873 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 return element;
875 }
876 }
877 }
878 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800879}
880
881
Dmitry-Me886ad972015-07-22 11:00:51 +0300882const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800883{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300884 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
885 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300887 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 return element;
889 }
890 }
891 }
892 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800893}
894
895
Dmitry-Me886ad972015-07-22 11:00:51 +0300896const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800897{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300898 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400899 const XMLElement* element = node->ToElement();
900 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300901 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 }
905 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800906}
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400912 const XMLElement* element = node->ToElement();
913 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300914 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400915 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 }
917 }
918 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800919}
920
921
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800922char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800923{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 // This is a recursive method, but thinking about it "at the current level"
925 // it is a pretty simple flat list:
926 // <foo/>
927 // <!-- comment -->
928 //
929 // With a special case:
930 // <foo>
931 // </foo>
932 // <!-- comment -->
933 //
934 // Where the closing element (/foo) *must* be the next thing after the opening
935 // element, and the names must match. BUT the tricky bit is that the closing
936 // element will be read by the child.
937 //
938 // 'endTag' is the end tag for this node, it is returned by a call to a child.
939 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800940
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 while( p && *p ) {
942 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800943
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300945 if ( node == 0 ) {
946 break;
947 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800948
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 StrPair endTag;
950 p = node->ParseDeep( p, &endTag );
951 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400952 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 if ( !_document->Error() ) {
954 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 break;
957 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800958
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530959 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530960 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530961 // A declaration can only be the first child of a document.
962 // Set error, if document already has children.
963 if ( !_document->NoChildren() ) {
964 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
965 DeleteNode( decl );
966 break;
967 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530968 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530969
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400970 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500972 // We read the end tag. Return it to the parent.
973 if ( ele->ClosingType() == XMLElement::CLOSING ) {
974 if ( parentEnd ) {
975 ele->_value.TransferTo( parentEnd );
976 }
977 node->_memPool->SetTracked(); // created and then immediately deleted.
978 DeleteNode( node );
979 return p;
980 }
981
982 // Handle an end tag returned to this level.
983 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400984 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300985 if ( endTag.Empty() ) {
986 if ( ele->ClosingType() == XMLElement::OPEN ) {
987 mismatch = true;
988 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300990 else {
991 if ( ele->ClosingType() != XMLElement::OPEN ) {
992 mismatch = true;
993 }
Dmitry-Me886ad972015-07-22 11:00:51 +0300994 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400995 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 }
997 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400998 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300999 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001000 DeleteNode( node );
1001 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001002 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 }
JayXondbfdd8f2014-12-12 20:07:14 -05001004 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 }
1006 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001007}
1008
Dmitry-Mee3225b12014-09-03 11:03:11 +04001009void XMLNode::DeleteNode( XMLNode* node )
1010{
1011 if ( node == 0 ) {
1012 return;
1013 }
1014 MemPool* pool = node->_memPool;
1015 node->~XMLNode();
1016 pool->Free( node );
1017}
1018
Lee Thomason3cebdc42015-01-05 17:16:28 -08001019void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001020{
1021 TIXMLASSERT( insertThis );
1022 TIXMLASSERT( insertThis->_document == _document );
1023
1024 if ( insertThis->_parent )
1025 insertThis->_parent->Unlink( insertThis );
1026 else
1027 insertThis->_memPool->SetTracked();
1028}
1029
Lee Thomason5492a1c2012-01-23 15:32:10 -08001030// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 const char* start = p;
1034 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001035 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 return p;
1040 }
1041 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1043 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001044 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001046
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( p && *p ) {
1049 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001050 }
1051 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001052 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 }
1054 }
1055 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001056}
1057
1058
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001059XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1060{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001062 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 }
1064 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1065 text->SetCData( this->CData() );
1066 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001067}
1068
1069
1070bool XMLText::ShallowEqual( const XMLNode* compare ) const
1071{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001072 const XMLText* text = compare->ToText();
1073 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001074}
1075
1076
Lee Thomason56bdd022012-02-09 18:16:58 -08001077bool XMLText::Accept( XMLVisitor* visitor ) const
1078{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001079 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001081}
1082
1083
Lee Thomason3f57d272012-01-11 15:30:03 -08001084// --------- XMLComment ---------- //
1085
Lee Thomasone4422302012-01-20 17:59:50 -08001086XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001087{
1088}
1089
1090
Lee Thomasonce0763e2012-01-11 15:43:54 -08001091XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001092{
Lee Thomason3f57d272012-01-11 15:30:03 -08001093}
1094
1095
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001096char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001097{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 // Comment parses as text.
1099 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001100 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001102 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 }
1104 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001105}
1106
1107
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001108XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001111 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 }
1113 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1114 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001115}
1116
1117
1118bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1119{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001120 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001121 const XMLComment* comment = compare->ToComment();
1122 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123}
1124
1125
Lee Thomason751da522012-02-10 08:50:51 -08001126bool XMLComment::Accept( XMLVisitor* visitor ) const
1127{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001128 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001130}
Lee Thomason56bdd022012-02-09 18:16:58 -08001131
1132
Lee Thomason50f97b22012-02-11 16:33:40 -08001133// --------- XMLDeclaration ---------- //
1134
1135XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1136{
1137}
1138
1139
1140XMLDeclaration::~XMLDeclaration()
1141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001143}
1144
1145
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001146char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 // Declaration parses as text.
1149 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001150 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 }
1154 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001155}
1156
1157
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001158XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 }
1163 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1164 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001165}
1166
1167
1168bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1169{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001170 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001171 const XMLDeclaration* declaration = compare->ToDeclaration();
1172 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001173}
1174
1175
1176
Lee Thomason50f97b22012-02-11 16:33:40 -08001177bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1178{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001179 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001181}
1182
1183// --------- XMLUnknown ---------- //
1184
1185XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1186{
1187}
1188
1189
1190XMLUnknown::~XMLUnknown()
1191{
1192}
1193
1194
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001195char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 // Unknown parses as text.
1198 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001199
Lee Thomason624d43f2012-10-12 10:58:48 -07001200 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 }
1204 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001205}
1206
1207
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001208XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 }
1213 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1214 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001215}
1216
1217
1218bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1219{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001220 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001221 const XMLUnknown* unknown = compare->ToUnknown();
1222 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001223}
1224
1225
Lee Thomason50f97b22012-02-11 16:33:40 -08001226bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1227{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001228 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001230}
1231
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001232// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001233
1234const char* XMLAttribute::Name() const
1235{
1236 return _name.GetStr();
1237}
1238
1239const char* XMLAttribute::Value() const
1240{
1241 return _value.GetStr();
1242}
1243
Lee Thomason6f381b72012-03-02 12:59:39 -08001244char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 if ( !p || !*p ) {
1249 return 0;
1250 }
Lee Thomason22aead12012-01-23 13:29:35 -08001251
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 // Skip white space before =
1253 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001254 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 return 0;
1256 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001257
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 ++p; // move up to opening quote
1259 p = XMLUtil::SkipWhiteSpace( p );
1260 if ( *p != '\"' && *p != '\'' ) {
1261 return 0;
1262 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001263
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 char endTag[2] = { *p, 0 };
1265 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001266
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269}
1270
1271
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001272void XMLAttribute::SetName( const char* n )
1273{
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001275}
1276
1277
Lee Thomason2fa81722012-11-09 12:37:46 -08001278XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 if ( XMLUtil::ToInt( Value(), value )) {
1281 return XML_NO_ERROR;
1282 }
1283 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001284}
1285
1286
Lee Thomason2fa81722012-11-09 12:37:46 -08001287XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 if ( XMLUtil::ToUnsigned( Value(), value )) {
1290 return XML_NO_ERROR;
1291 }
1292 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001293}
1294
1295
Lee Thomason2fa81722012-11-09 12:37:46 -08001296XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 if ( XMLUtil::ToBool( Value(), value )) {
1299 return XML_NO_ERROR;
1300 }
1301 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001302}
1303
1304
Lee Thomason2fa81722012-11-09 12:37:46 -08001305XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 if ( XMLUtil::ToFloat( Value(), value )) {
1308 return XML_NO_ERROR;
1309 }
1310 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001311}
1312
1313
Lee Thomason2fa81722012-11-09 12:37:46 -08001314XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( XMLUtil::ToDouble( Value(), value )) {
1317 return XML_NO_ERROR;
1318 }
1319 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001320}
1321
1322
1323void XMLAttribute::SetAttribute( const char* v )
1324{
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001326}
1327
1328
Lee Thomason1ff38e02012-02-14 18:18:16 -08001329void XMLAttribute::SetAttribute( int v )
1330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 char buf[BUF_SIZE];
1332 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001333 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001334}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001335
1336
1337void XMLAttribute::SetAttribute( unsigned v )
1338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001341 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001342}
1343
1344
1345void XMLAttribute::SetAttribute( bool v )
1346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001350}
1351
1352void XMLAttribute::SetAttribute( double v )
1353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 char buf[BUF_SIZE];
1355 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001357}
1358
1359void XMLAttribute::SetAttribute( float v )
1360{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 char buf[BUF_SIZE];
1362 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001364}
1365
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001366
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001367// --------- XMLElement ---------- //
1368XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 _closingType( 0 ),
1370 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371{
1372}
1373
1374
1375XMLElement::~XMLElement()
1376{
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 while( _rootAttribute ) {
1378 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001379 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001380 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001382}
1383
1384
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001385const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1386{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001387 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1389 return a;
1390 }
1391 }
1392 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393}
1394
1395
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001396const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 const XMLAttribute* a = FindAttribute( name );
1399 if ( !a ) {
1400 return 0;
1401 }
1402 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1403 return a->Value();
1404 }
1405 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001406}
1407
1408
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001409const char* XMLElement::GetText() const
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001412 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 }
1414 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001415}
1416
1417
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001418void XMLElement::SetText( const char* inText )
1419{
Uli Kusterer869bb592014-01-21 01:36:16 +01001420 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001421 FirstChild()->SetValue( inText );
1422 else {
1423 XMLText* theText = GetDocument()->NewText( inText );
1424 InsertFirstChild( theText );
1425 }
1426}
1427
Lee Thomason5bb2d802014-01-24 10:42:57 -08001428
1429void XMLElement::SetText( int v )
1430{
1431 char buf[BUF_SIZE];
1432 XMLUtil::ToStr( v, buf, BUF_SIZE );
1433 SetText( buf );
1434}
1435
1436
1437void XMLElement::SetText( unsigned v )
1438{
1439 char buf[BUF_SIZE];
1440 XMLUtil::ToStr( v, buf, BUF_SIZE );
1441 SetText( buf );
1442}
1443
1444
1445void XMLElement::SetText( bool v )
1446{
1447 char buf[BUF_SIZE];
1448 XMLUtil::ToStr( v, buf, BUF_SIZE );
1449 SetText( buf );
1450}
1451
1452
1453void XMLElement::SetText( float v )
1454{
1455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
1457 SetText( buf );
1458}
1459
1460
1461void XMLElement::SetText( double v )
1462{
1463 char buf[BUF_SIZE];
1464 XMLUtil::ToStr( v, buf, BUF_SIZE );
1465 SetText( buf );
1466}
1467
1468
MortenMacFly4ee49f12013-01-14 20:03:14 +01001469XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001472 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001473 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 return XML_SUCCESS;
1475 }
1476 return XML_CAN_NOT_CONVERT_TEXT;
1477 }
1478 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001479}
1480
1481
MortenMacFly4ee49f12013-01-14 20:03:14 +01001482XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001483{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001485 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001486 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 return XML_SUCCESS;
1488 }
1489 return XML_CAN_NOT_CONVERT_TEXT;
1490 }
1491 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001492}
1493
1494
MortenMacFly4ee49f12013-01-14 20:03:14 +01001495XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001498 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001499 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 return XML_SUCCESS;
1501 }
1502 return XML_CAN_NOT_CONVERT_TEXT;
1503 }
1504 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001505}
1506
1507
MortenMacFly4ee49f12013-01-14 20:03:14 +01001508XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001509{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001511 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001512 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 return XML_SUCCESS;
1514 }
1515 return XML_CAN_NOT_CONVERT_TEXT;
1516 }
1517 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001518}
1519
1520
MortenMacFly4ee49f12013-01-14 20:03:14 +01001521XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001524 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001525 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 return XML_SUCCESS;
1527 }
1528 return XML_CAN_NOT_CONVERT_TEXT;
1529 }
1530 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001531}
1532
1533
1534
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001535XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 XMLAttribute* last = 0;
1538 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1543 break;
1544 }
1545 }
1546 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001547 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1549 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001551 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 }
1553 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 }
1556 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001557 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 }
1559 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001560}
1561
1562
U-Stream\Leeae25a442012-02-17 17:48:16 -08001563void XMLElement::DeleteAttribute( const char* name )
1564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001566 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1568 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001574 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 break;
1576 }
1577 prev = a;
1578 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001579}
1580
1581
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001582char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 const char* start = p;
1585 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001586
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 // Read the attributes.
1588 while( p ) {
1589 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001590 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001591 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 return 0;
1593 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001594
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001596 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001597 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1599 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001600 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001601
Lee Thomason624d43f2012-10-12 10:58:48 -07001602 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001604 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 return 0;
1607 }
1608 // There is a minor bug here: if the attribute in the source xml
1609 // document is duplicated, it will not be detected and the
1610 // attribute will be doubly added. However, tracking the 'prevAttribute'
1611 // avoids re-scanning the attribute list. Preferring performance for
1612 // now, may reconsider in the future.
1613 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 }
1616 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 prevAttribute = attrib;
1620 }
1621 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 else if ( *p == '>' ) {
1623 ++p;
1624 break;
1625 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001626 // end of the tag
1627 else if ( *p == '/' && *(p+1) == '>' ) {
1628 _closingType = CLOSED;
1629 return p+2; // done; sealed element.
1630 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 return 0;
1634 }
1635 }
1636 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001637}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001638
Dmitry-Mee3225b12014-09-03 11:03:11 +04001639void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1640{
1641 if ( attribute == 0 ) {
1642 return;
1643 }
1644 MemPool* pool = attribute->_memPool;
1645 attribute->~XMLAttribute();
1646 pool->Free( attribute );
1647}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001648
Lee Thomason67d61312012-01-24 16:01:51 -08001649//
1650// <ele></ele>
1651// <ele>foo<b>bar</b></ele>
1652//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001653char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001654{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 // Read the element name.
1656 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001657
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 // The closing element is the </element> form. It is
1659 // parsed just like a regular element then deleted from
1660 // the DOM.
1661 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 ++p;
1664 }
Lee Thomason67d61312012-01-24 16:01:51 -08001665
Lee Thomason624d43f2012-10-12 10:58:48 -07001666 p = _value.ParseName( p );
1667 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 return 0;
1669 }
Lee Thomason67d61312012-01-24 16:01:51 -08001670
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 return p;
1674 }
Lee Thomason67d61312012-01-24 16:01:51 -08001675
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 p = XMLNode::ParseDeep( p, strPair );
1677 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001678}
1679
1680
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001681
1682XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1683{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 }
1687 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1688 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1689 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1690 }
1691 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001692}
1693
1694
1695bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1696{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001697 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001699 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001700
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 const XMLAttribute* a=FirstAttribute();
1702 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001703
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 while ( a && b ) {
1705 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1706 return false;
1707 }
1708 a = a->Next();
1709 b = b->Next();
1710 }
1711 if ( a || b ) {
1712 // different count
1713 return false;
1714 }
1715 return true;
1716 }
1717 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001718}
1719
1720
Lee Thomason751da522012-02-10 08:50:51 -08001721bool XMLElement::Accept( XMLVisitor* visitor ) const
1722{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001723 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1726 if ( !node->Accept( visitor ) ) {
1727 break;
1728 }
1729 }
1730 }
1731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001732}
Lee Thomason56bdd022012-02-09 18:16:58 -08001733
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001734
Lee Thomason3f57d272012-01-11 15:30:03 -08001735// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001736
1737// Warning: List must match 'enum XMLError'
1738const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1739 "XML_SUCCESS",
1740 "XML_NO_ATTRIBUTE",
1741 "XML_WRONG_ATTRIBUTE_TYPE",
1742 "XML_ERROR_FILE_NOT_FOUND",
1743 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1744 "XML_ERROR_FILE_READ_ERROR",
1745 "XML_ERROR_ELEMENT_MISMATCH",
1746 "XML_ERROR_PARSING_ELEMENT",
1747 "XML_ERROR_PARSING_ATTRIBUTE",
1748 "XML_ERROR_IDENTIFYING_TAG",
1749 "XML_ERROR_PARSING_TEXT",
1750 "XML_ERROR_PARSING_CDATA",
1751 "XML_ERROR_PARSING_COMMENT",
1752 "XML_ERROR_PARSING_DECLARATION",
1753 "XML_ERROR_PARSING_UNKNOWN",
1754 "XML_ERROR_EMPTY_DOCUMENT",
1755 "XML_ERROR_MISMATCHED_ELEMENT",
1756 "XML_ERROR_PARSING",
1757 "XML_CAN_NOT_CONVERT_TEXT",
1758 "XML_NO_TEXT_NODE"
1759};
1760
1761
Lee Thomason624d43f2012-10-12 10:58:48 -07001762XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 _writeBOM( false ),
1765 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001766 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 _whitespace( whitespace ),
1768 _errorStr1( 0 ),
1769 _errorStr2( 0 ),
1770 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001771{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001772 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1773 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001774}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001775
1776
Lee Thomason3f57d272012-01-11 15:30:03 -08001777XMLDocument::~XMLDocument()
1778{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001779 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001780}
1781
1782
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001783void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001784{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001785 DeleteChildren();
1786
Dmitry-Meab37df82014-11-28 12:08:36 +03001787#ifdef DEBUG
1788 const bool hadError = Error();
1789#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 _errorID = XML_NO_ERROR;
1791 _errorStr1 = 0;
1792 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001793
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 delete [] _charBuffer;
1795 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001796
1797#if 0
1798 _textPool.Trace( "text" );
1799 _elementPool.Trace( "element" );
1800 _commentPool.Trace( "comment" );
1801 _attributePool.Trace( "attribute" );
1802#endif
1803
1804#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001805 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001806 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1807 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1808 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1809 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1810 }
1811#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001812}
1813
Lee Thomason3f57d272012-01-11 15:30:03 -08001814
Lee Thomason2c85a712012-01-31 08:24:24 -08001815XMLElement* XMLDocument::NewElement( const char* name )
1816{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001817 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1819 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 ele->SetName( name );
1821 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001822}
1823
1824
Lee Thomason1ff38e02012-02-14 18:18:16 -08001825XMLComment* XMLDocument::NewComment( const char* str )
1826{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001827 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1829 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 comment->SetValue( str );
1831 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001832}
1833
1834
1835XMLText* XMLDocument::NewText( const char* str )
1836{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001837 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1839 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 text->SetValue( str );
1841 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001842}
1843
1844
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001845XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1846{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001847 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1849 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1851 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001852}
1853
1854
1855XMLUnknown* XMLDocument::NewUnknown( const char* str )
1856{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001857 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1859 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 unk->SetValue( str );
1861 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001862}
1863
Dmitry-Me01578db2014-08-19 10:18:48 +04001864static FILE* callfopen( const char* filepath, const char* mode )
1865{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001866 TIXMLASSERT( filepath );
1867 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001868#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1869 FILE* fp = 0;
1870 errno_t err = fopen_s( &fp, filepath, mode );
1871 if ( err ) {
1872 return 0;
1873 }
1874#else
1875 FILE* fp = fopen( filepath, mode );
1876#endif
1877 return fp;
1878}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001879
1880void XMLDocument::DeleteNode( XMLNode* node ) {
1881 TIXMLASSERT( node );
1882 TIXMLASSERT(node->_document == this );
1883 if (node->_parent) {
1884 node->_parent->DeleteChild( node );
1885 }
1886 else {
1887 // Isn't in the tree.
1888 // Use the parent delete.
1889 // Also, we need to mark it tracked: we 'know'
1890 // it was never used.
1891 node->_memPool->SetTracked();
1892 // Call the static XMLNode version:
1893 XMLNode::DeleteNode(node);
1894 }
1895}
1896
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001897
Lee Thomason2fa81722012-11-09 12:37:46 -08001898XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001899{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001900 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001901 FILE* fp = callfopen( filename, "rb" );
1902 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 }
1906 LoadFile( fp );
1907 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001909}
1910
1911
Lee Thomason2fa81722012-11-09 12:37:46 -08001912XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001913{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001914 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001915
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001916 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001917 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001918 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1919 return _errorID;
1920 }
1921
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001923 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001925 if ( filelength == -1L ) {
1926 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1927 return _errorID;
1928 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001929
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001930 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001931 // Cannot handle files which won't fit in buffer together with null terminator
1932 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1933 return _errorID;
1934 }
1935
Dmitry-Me72801b82015-05-07 09:41:39 +03001936 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001937 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001940
Dmitry-Me72801b82015-05-07 09:41:39 +03001941 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 _charBuffer = new char[size+1];
1943 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 if ( read != size ) {
1945 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001948
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001950
Dmitry-Me97476b72015-01-01 16:15:57 +03001951 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001953}
1954
1955
Lee Thomason2fa81722012-11-09 12:37:46 -08001956XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001957{
Dmitry-Me01578db2014-08-19 10:18:48 +04001958 FILE* fp = callfopen( filename, "w" );
1959 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 }
1963 SaveFile(fp, compact);
1964 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001965 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001966}
1967
1968
Lee Thomason2fa81722012-11-09 12:37:46 -08001969XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001970{
Ant Mitchell189198f2015-03-24 16:20:36 +00001971 // Clear any error from the last save, otherwise it will get reported
1972 // for *this* call.
1973 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 XMLPrinter stream( fp, compact );
1975 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977}
1978
Lee Thomason1ff38e02012-02-14 18:18:16 -08001979
Lee Thomason2fa81722012-11-09 12:37:46 -08001980XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001981{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001982 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001983
Lee Thomason82d32002014-02-21 22:47:18 -08001984 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001986 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 }
1988 if ( len == (size_t)(-1) ) {
1989 len = strlen( p );
1990 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 _charBuffer = new char[ len+1 ];
1992 memcpy( _charBuffer, p, len );
1993 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001994
Dmitry-Me97476b72015-01-01 16:15:57 +03001995 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001996 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001997 // clean up now essentially dangling memory.
1998 // and the parse fail can put objects in the
1999 // pools that are dead and inaccessible.
2000 DeleteChildren();
2001 _elementPool.Clear();
2002 _attributePool.Clear();
2003 _textPool.Clear();
2004 _commentPool.Clear();
2005 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002007}
2008
2009
PKEuS1c5f99e2013-07-06 11:28:39 +02002010void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002011{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002012 if ( streamer ) {
2013 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002015 else {
2016 XMLPrinter stdoutStreamer( stdout );
2017 Accept( &stdoutStreamer );
2018 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002019}
2020
2021
Lee Thomason2fa81722012-11-09 12:37:46 -08002022void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002023{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002024 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 _errorID = error;
2026 _errorStr1 = str1;
2027 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002028}
2029
Lee Thomason331596e2014-09-11 14:56:43 -07002030const char* XMLDocument::ErrorName() const
2031{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002032 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002033 const char* errorName = _errorNames[_errorID];
2034 TIXMLASSERT( errorName && errorName[0] );
2035 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002036}
Lee Thomason5cae8972012-01-24 18:03:07 -08002037
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002038void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002039{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002040 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 static const int LEN = 20;
2042 char buf1[LEN] = { 0 };
2043 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002044
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 if ( _errorStr1 ) {
2046 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _errorStr2 ) {
2049 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002051
Dmitry-Me2ad43202015-04-16 12:18:58 +03002052 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2053 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2054 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002055 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002056 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002058}
2059
Dmitry-Me97476b72015-01-01 16:15:57 +03002060void XMLDocument::Parse()
2061{
2062 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2063 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002064 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002065 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002066 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002067 if ( !*p ) {
2068 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2069 return;
2070 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002071 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002072}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002073
PKEuS1bfb9542013-08-04 13:51:17 +02002074XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 _elementJustOpened( false ),
2076 _firstElement( true ),
2077 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002078 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 _textDepth( -1 ),
2080 _processEntities( true ),
2081 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 _entityFlag[i] = false;
2085 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 }
2087 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002088 const char entityValue = entities[i].value;
2089 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2090 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002092 _restrictedEntityFlag[(unsigned char)'&'] = true;
2093 _restrictedEntityFlag[(unsigned char)'<'] = true;
2094 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002096}
2097
2098
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002099void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002100{
2101 va_list va;
2102 va_start( va, format );
2103
Lee Thomason624d43f2012-10-12 10:58:48 -07002104 if ( _fp ) {
2105 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 }
2107 else {
pffang1527cf42015-06-09 13:57:11 +08002108 int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 // Close out and re-start the va-args
2110 va_end( va );
2111 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002112 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002113 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002114 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002116 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002117}
2118
2119
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002120void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 for( int i=0; i<depth; ++i ) {
2123 Print( " " );
2124 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002125}
2126
2127
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002128void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 // Look for runs of bytes between entities to print.
2131 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002132
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002134 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002136 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 // Remember, char is sometimes signed. (How many times has that bitten me?)
2138 if ( *q > 0 && *q < ENTITY_RANGE ) {
2139 // Check for entities. If one is found, flush
2140 // the stream up until the entity, write the
2141 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002142 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002144 const size_t delta = q - p;
2145 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002146 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002147 Print( "%.*s", toPrint, p );
2148 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002150 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 for( int i=0; i<NUM_ENTITIES; ++i ) {
2152 if ( entities[i].value == *q ) {
2153 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002154 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 break;
2156 }
2157 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002158 if ( !entityPatternPrinted ) {
2159 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2160 TIXMLASSERT( false );
2161 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 ++p;
2163 }
2164 }
2165 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002166 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 }
2168 }
2169 // Flush the remaining string. This will be the entire
2170 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002171 TIXMLASSERT( p <= q );
2172 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 Print( "%s", p );
2174 }
Lee Thomason857b8682012-01-25 17:50:25 -08002175}
2176
U-Stream\Leeae25a442012-02-17 17:48:16 -08002177
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002178void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002181 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 -07002182 Print( "%s", bom );
2183 }
2184 if ( writeDec ) {
2185 PushDeclaration( "xml version=\"1.0\"" );
2186 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002187}
2188
2189
Uli Kusterer593a33d2014-02-01 12:48:51 +01002190void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002191{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002192 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002194
Uli Kusterer593a33d2014-02-01 12:48:51 +01002195 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002197 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002198 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002201
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 _elementJustOpened = true;
2204 _firstElement = false;
2205 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002206}
2207
2208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002210{
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 Print( " %s=\"", name );
2213 PrintString( value, false );
2214 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002215}
2216
2217
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002218void XMLPrinter::PushAttribute( const char* name, int v )
2219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 char buf[BUF_SIZE];
2221 XMLUtil::ToStr( v, buf, BUF_SIZE );
2222 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002223}
2224
2225
2226void XMLPrinter::PushAttribute( const char* name, unsigned v )
2227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 char buf[BUF_SIZE];
2229 XMLUtil::ToStr( v, buf, BUF_SIZE );
2230 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002231}
2232
2233
2234void XMLPrinter::PushAttribute( const char* name, bool v )
2235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 char buf[BUF_SIZE];
2237 XMLUtil::ToStr( v, buf, BUF_SIZE );
2238 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002239}
2240
2241
2242void XMLPrinter::PushAttribute( const char* name, double v )
2243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 char buf[BUF_SIZE];
2245 XMLUtil::ToStr( v, buf, BUF_SIZE );
2246 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002247}
2248
2249
Uli Kustererca412e82014-02-01 13:35:05 +01002250void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002251{
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 --_depth;
2253 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002254
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 Print( "/>" );
2257 }
2258 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002259 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 }
2263 Print( "</%s>", name );
2264 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002265
Lee Thomason624d43f2012-10-12 10:58:48 -07002266 if ( _textDepth == _depth ) {
2267 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 }
Uli Kustererca412e82014-02-01 13:35:05 +01002269 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 Print( "\n" );
2271 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002272 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002273}
2274
2275
Dmitry-Mea092bc12014-12-23 17:57:05 +03002276void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002277{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002278 if ( !_elementJustOpened ) {
2279 return;
2280 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002283}
2284
2285
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002286void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002287{
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002289
Dmitry-Mea092bc12014-12-23 17:57:05 +03002290 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002292 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 }
2294 else {
2295 PrintString( text, true );
2296 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002297}
2298
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002299void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 char buf[BUF_SIZE];
2302 XMLUtil::ToStr( value, buf, BUF_SIZE );
2303 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002304}
2305
2306
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002307void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 char buf[BUF_SIZE];
2310 XMLUtil::ToStr( value, buf, BUF_SIZE );
2311 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002312}
2313
2314
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002315void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 char buf[BUF_SIZE];
2318 XMLUtil::ToStr( value, buf, BUF_SIZE );
2319 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002320}
2321
2322
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002323void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002324{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 char buf[BUF_SIZE];
2326 XMLUtil::ToStr( value, buf, BUF_SIZE );
2327 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002328}
2329
2330
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002331void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 char buf[BUF_SIZE];
2334 XMLUtil::ToStr( value, buf, BUF_SIZE );
2335 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002336}
2337
Lee Thomason5cae8972012-01-24 18:03:07 -08002338
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002339void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002340{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002341 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002342 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002343 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002344 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002346 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002348}
Lee Thomason751da522012-02-10 08:50:51 -08002349
2350
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002351void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002352{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002353 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002360}
2361
2362
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002363void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002364{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002365 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002366 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002368 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002372}
2373
2374
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002375bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002376{
Lee Thomason624d43f2012-10-12 10:58:48 -07002377 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 if ( doc.HasBOM() ) {
2379 PushHeader( true, false );
2380 }
2381 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002382}
2383
2384
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002385bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002386{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002387 const XMLElement* parentElem = 0;
2388 if ( element.Parent() ) {
2389 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002390 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002391 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002392 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 while ( attribute ) {
2394 PushAttribute( attribute->Name(), attribute->Value() );
2395 attribute = attribute->Next();
2396 }
2397 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002398}
2399
2400
Uli Kustererca412e82014-02-01 13:35:05 +01002401bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002402{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002403 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002405}
2406
2407
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002408bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 PushText( text.Value(), text.CData() );
2411 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002412}
2413
2414
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002415bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 PushComment( comment.Value() );
2418 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002419}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002420
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002421bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 PushDeclaration( declaration.Value() );
2424 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002425}
2426
2427
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002428bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 PushUnknown( unknown.Value() );
2431 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002432}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002433
Lee Thomason685b8952012-11-12 13:00:06 -08002434} // namespace tinyxml2
2435