blob: 356a598c6632530efb93c60d8114dee6518de886 [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)
34 // Microsoft visual studio, version 2005 and higher. Not WinCE.
35 /*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
Lee Thomason56bdd022012-02-09 18:16:58 -0800868const XMLElement* XMLNode::FirstChildElement( const char* value ) 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 ) {
873 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
874 return element;
875 }
876 }
877 }
878 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800879}
880
881
Lee Thomason56bdd022012-02-09 18:16:58 -0800882const XMLElement* XMLNode::LastChildElement( const char* value ) const
883{
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 ) {
887 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
888 return element;
889 }
890 }
891 }
892 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800893}
894
895
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800896const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
897{
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
901 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 }
905 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800906}
907
908
909const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
910{
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
914 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
915 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 }
994 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
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 ) {
999 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 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();
1699 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
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{
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001773}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001774
1775
Lee Thomason3f57d272012-01-11 15:30:03 -08001776XMLDocument::~XMLDocument()
1777{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001778 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001779}
1780
1781
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001782void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001783{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001784 DeleteChildren();
1785
Dmitry-Meab37df82014-11-28 12:08:36 +03001786#ifdef DEBUG
1787 const bool hadError = Error();
1788#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 _errorID = XML_NO_ERROR;
1790 _errorStr1 = 0;
1791 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001792
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 delete [] _charBuffer;
1794 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001795
1796#if 0
1797 _textPool.Trace( "text" );
1798 _elementPool.Trace( "element" );
1799 _commentPool.Trace( "comment" );
1800 _attributePool.Trace( "attribute" );
1801#endif
1802
1803#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001804 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001805 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1806 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1807 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1808 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1809 }
1810#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001811}
1812
Lee Thomason3f57d272012-01-11 15:30:03 -08001813
Lee Thomason2c85a712012-01-31 08:24:24 -08001814XMLElement* XMLDocument::NewElement( const char* name )
1815{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001816 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1818 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 ele->SetName( name );
1820 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001821}
1822
1823
Lee Thomason1ff38e02012-02-14 18:18:16 -08001824XMLComment* XMLDocument::NewComment( const char* str )
1825{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001826 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1828 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 comment->SetValue( str );
1830 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001831}
1832
1833
1834XMLText* XMLDocument::NewText( const char* str )
1835{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001836 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1838 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 text->SetValue( str );
1840 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001841}
1842
1843
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001844XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1845{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001846 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1848 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1850 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001851}
1852
1853
1854XMLUnknown* XMLDocument::NewUnknown( const char* str )
1855{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001856 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1858 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 unk->SetValue( str );
1860 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001861}
1862
Dmitry-Me01578db2014-08-19 10:18:48 +04001863static FILE* callfopen( const char* filepath, const char* mode )
1864{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001865 TIXMLASSERT( filepath );
1866 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001867#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1868 FILE* fp = 0;
1869 errno_t err = fopen_s( &fp, filepath, mode );
1870 if ( err ) {
1871 return 0;
1872 }
1873#else
1874 FILE* fp = fopen( filepath, mode );
1875#endif
1876 return fp;
1877}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001878
1879void XMLDocument::DeleteNode( XMLNode* node ) {
1880 TIXMLASSERT( node );
1881 TIXMLASSERT(node->_document == this );
1882 if (node->_parent) {
1883 node->_parent->DeleteChild( node );
1884 }
1885 else {
1886 // Isn't in the tree.
1887 // Use the parent delete.
1888 // Also, we need to mark it tracked: we 'know'
1889 // it was never used.
1890 node->_memPool->SetTracked();
1891 // Call the static XMLNode version:
1892 XMLNode::DeleteNode(node);
1893 }
1894}
1895
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001896
Lee Thomason2fa81722012-11-09 12:37:46 -08001897XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001898{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001899 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001900 FILE* fp = callfopen( filename, "rb" );
1901 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 }
1905 LoadFile( fp );
1906 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001908}
1909
1910
Lee Thomason2fa81722012-11-09 12:37:46 -08001911XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001913 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001914
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001915 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001916 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001917 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1918 return _errorID;
1919 }
1920
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001922 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001924 if ( filelength == -1L ) {
1925 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1926 return _errorID;
1927 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001928
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001929 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001930 // Cannot handle files which won't fit in buffer together with null terminator
1931 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1932 return _errorID;
1933 }
1934
Dmitry-Me72801b82015-05-07 09:41:39 +03001935 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001936 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001939
Dmitry-Me72801b82015-05-07 09:41:39 +03001940 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 _charBuffer = new char[size+1];
1942 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 if ( read != size ) {
1944 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001947
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001949
Dmitry-Me97476b72015-01-01 16:15:57 +03001950 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001952}
1953
1954
Lee Thomason2fa81722012-11-09 12:37:46 -08001955XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001956{
Dmitry-Me01578db2014-08-19 10:18:48 +04001957 FILE* fp = callfopen( filename, "w" );
1958 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 }
1962 SaveFile(fp, compact);
1963 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001965}
1966
1967
Lee Thomason2fa81722012-11-09 12:37:46 -08001968XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001969{
Ant Mitchell189198f2015-03-24 16:20:36 +00001970 // Clear any error from the last save, otherwise it will get reported
1971 // for *this* call.
1972 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 XMLPrinter stream( fp, compact );
1974 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001976}
1977
Lee Thomason1ff38e02012-02-14 18:18:16 -08001978
Lee Thomason2fa81722012-11-09 12:37:46 -08001979XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001980{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001981 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001982
Lee Thomason82d32002014-02-21 22:47:18 -08001983 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001984 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 }
1987 if ( len == (size_t)(-1) ) {
1988 len = strlen( p );
1989 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001990 _charBuffer = new char[ len+1 ];
1991 memcpy( _charBuffer, p, len );
1992 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001993
Dmitry-Me97476b72015-01-01 16:15:57 +03001994 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001995 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001996 // clean up now essentially dangling memory.
1997 // and the parse fail can put objects in the
1998 // pools that are dead and inaccessible.
1999 DeleteChildren();
2000 _elementPool.Clear();
2001 _attributePool.Clear();
2002 _textPool.Clear();
2003 _commentPool.Clear();
2004 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002005 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002006}
2007
2008
PKEuS1c5f99e2013-07-06 11:28:39 +02002009void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002010{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002011 if ( streamer ) {
2012 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002014 else {
2015 XMLPrinter stdoutStreamer( stdout );
2016 Accept( &stdoutStreamer );
2017 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002018}
2019
2020
Lee Thomason2fa81722012-11-09 12:37:46 -08002021void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002022{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002023 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 _errorID = error;
2025 _errorStr1 = str1;
2026 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002027}
2028
Lee Thomason331596e2014-09-11 14:56:43 -07002029const char* XMLDocument::ErrorName() const
2030{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002031 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002032 const char* errorName = _errorNames[_errorID];
2033 TIXMLASSERT( errorName && errorName[0] );
2034 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002035}
Lee Thomason5cae8972012-01-24 18:03:07 -08002036
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002037void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002038{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002039 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 static const int LEN = 20;
2041 char buf1[LEN] = { 0 };
2042 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 if ( _errorStr1 ) {
2045 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002047 if ( _errorStr2 ) {
2048 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002050
Dmitry-Me2ad43202015-04-16 12:18:58 +03002051 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2052 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2053 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002054 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002055 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002057}
2058
Dmitry-Me97476b72015-01-01 16:15:57 +03002059void XMLDocument::Parse()
2060{
2061 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2062 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002063 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002064 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002065 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002066 if ( !*p ) {
2067 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2068 return;
2069 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002070 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002071}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002072
PKEuS1bfb9542013-08-04 13:51:17 +02002073XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 _elementJustOpened( false ),
2075 _firstElement( true ),
2076 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002077 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _textDepth( -1 ),
2079 _processEntities( true ),
2080 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _entityFlag[i] = false;
2084 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 }
2086 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002087 const char entityValue = entities[i].value;
2088 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2089 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002091 _restrictedEntityFlag[(unsigned char)'&'] = true;
2092 _restrictedEntityFlag[(unsigned char)'<'] = true;
2093 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002095}
2096
2097
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002098void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002099{
2100 va_list va;
2101 va_start( va, format );
2102
Lee Thomason624d43f2012-10-12 10:58:48 -07002103 if ( _fp ) {
2104 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 }
2106 else {
pffang1527cf42015-06-09 13:57:11 +08002107 int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 // Close out and re-start the va-args
2109 va_end( va );
2110 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002111 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002112 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002113 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002115 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002116}
2117
2118
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002119void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002120{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 for( int i=0; i<depth; ++i ) {
2122 Print( " " );
2123 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002124}
2125
2126
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002127void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 // Look for runs of bytes between entities to print.
2130 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002131
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002133 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002135 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 // Remember, char is sometimes signed. (How many times has that bitten me?)
2137 if ( *q > 0 && *q < ENTITY_RANGE ) {
2138 // Check for entities. If one is found, flush
2139 // the stream up until the entity, write the
2140 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002141 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002143 const size_t delta = q - p;
2144 // %.*s accepts type int as "precision"
2145 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2146 Print( "%.*s", toPrint, p );
2147 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
2149 for( int i=0; i<NUM_ENTITIES; ++i ) {
2150 if ( entities[i].value == *q ) {
2151 Print( "&%s;", entities[i].pattern );
2152 break;
2153 }
2154 }
2155 ++p;
2156 }
2157 }
2158 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002159 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 }
2161 }
2162 // Flush the remaining string. This will be the entire
2163 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002164 TIXMLASSERT( p <= q );
2165 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 Print( "%s", p );
2167 }
Lee Thomason857b8682012-01-25 17:50:25 -08002168}
2169
U-Stream\Leeae25a442012-02-17 17:48:16 -08002170
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002171void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002174 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 -07002175 Print( "%s", bom );
2176 }
2177 if ( writeDec ) {
2178 PushDeclaration( "xml version=\"1.0\"" );
2179 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002180}
2181
2182
Uli Kusterer593a33d2014-02-01 12:48:51 +01002183void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002184{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002185 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002187
Uli Kusterer593a33d2014-02-01 12:48:51 +01002188 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002190 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002191 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002192 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002194
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002196 _elementJustOpened = true;
2197 _firstElement = false;
2198 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002199}
2200
2201
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002202void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002203{
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 Print( " %s=\"", name );
2206 PrintString( value, false );
2207 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002208}
2209
2210
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002211void XMLPrinter::PushAttribute( const char* name, int v )
2212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 char buf[BUF_SIZE];
2214 XMLUtil::ToStr( v, buf, BUF_SIZE );
2215 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002216}
2217
2218
2219void XMLPrinter::PushAttribute( const char* name, unsigned v )
2220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 char buf[BUF_SIZE];
2222 XMLUtil::ToStr( v, buf, BUF_SIZE );
2223 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002224}
2225
2226
2227void XMLPrinter::PushAttribute( const char* name, bool v )
2228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 char buf[BUF_SIZE];
2230 XMLUtil::ToStr( v, buf, BUF_SIZE );
2231 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002232}
2233
2234
2235void XMLPrinter::PushAttribute( const char* name, double v )
2236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 char buf[BUF_SIZE];
2238 XMLUtil::ToStr( v, buf, BUF_SIZE );
2239 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002240}
2241
2242
Uli Kustererca412e82014-02-01 13:35:05 +01002243void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002244{
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 --_depth;
2246 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002247
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 Print( "/>" );
2250 }
2251 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002252 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 }
2256 Print( "</%s>", name );
2257 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002258
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 if ( _textDepth == _depth ) {
2260 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 }
Uli Kustererca412e82014-02-01 13:35:05 +01002262 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 Print( "\n" );
2264 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002266}
2267
2268
Dmitry-Mea092bc12014-12-23 17:57:05 +03002269void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002270{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002271 if ( !_elementJustOpened ) {
2272 return;
2273 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002274 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002276}
2277
2278
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002279void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002280{
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002282
Dmitry-Mea092bc12014-12-23 17:57:05 +03002283 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002285 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 }
2287 else {
2288 PrintString( text, true );
2289 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002290}
2291
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002292void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 char buf[BUF_SIZE];
2295 XMLUtil::ToStr( value, buf, BUF_SIZE );
2296 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002297}
2298
2299
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002300void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 char buf[BUF_SIZE];
2303 XMLUtil::ToStr( value, buf, BUF_SIZE );
2304 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002305}
2306
2307
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002308void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 char buf[BUF_SIZE];
2311 XMLUtil::ToStr( value, buf, BUF_SIZE );
2312 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002313}
2314
2315
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002316void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002318 char buf[BUF_SIZE];
2319 XMLUtil::ToStr( value, buf, BUF_SIZE );
2320 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002321}
2322
2323
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002324void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002325{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002326 char buf[BUF_SIZE];
2327 XMLUtil::ToStr( value, buf, BUF_SIZE );
2328 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002329}
2330
Lee Thomason5cae8972012-01-24 18:03:07 -08002331
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002332void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002333{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002334 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002335 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002337 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002339 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002341}
Lee Thomason751da522012-02-10 08:50:51 -08002342
2343
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002344void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002345{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002346 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002347 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002349 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002352 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002353}
2354
2355
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002356void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002357{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002358 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002363 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002365}
2366
2367
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002368bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002369{
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 if ( doc.HasBOM() ) {
2372 PushHeader( true, false );
2373 }
2374 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002375}
2376
2377
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002378bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002379{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002380 const XMLElement* parentElem = 0;
2381 if ( element.Parent() ) {
2382 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002383 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002384 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002385 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 while ( attribute ) {
2387 PushAttribute( attribute->Name(), attribute->Value() );
2388 attribute = attribute->Next();
2389 }
2390 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002391}
2392
2393
Uli Kustererca412e82014-02-01 13:35:05 +01002394bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002395{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002396 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002398}
2399
2400
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002401bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 PushText( text.Value(), text.CData() );
2404 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 XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 PushComment( comment.Value() );
2411 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002412}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002413
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002414bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002416 PushDeclaration( declaration.Value() );
2417 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002418}
2419
2420
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002421bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 PushUnknown( unknown.Value() );
2424 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002425}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002426
Lee Thomason685b8952012-11-12 13:00:06 -08002427} // namespace tinyxml2
2428