blob: c1589ec5e661983ac977fbdd7dcf021b91f33402 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
44 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
45 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
53 inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
54 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
71 inline int TIXML_VSCPRINTF( const char* format, va_list va )
72 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
80 len = required;
81 break;
82 }
83 }
84 return len;
85 }
86 #endif
87#else
88 // GCC version 3 and higher
89 //#warning( "Using sn* functions." )
90 #define TIXML_SNPRINTF snprintf
91 #define TIXML_VSNPRINTF vsnprintf
92 inline int TIXML_VSCPRINTF( const char* format, va_list va )
93 {
94 int len = vsnprintf( 0, 0, format, va );
95 return len;
96 }
97 #define TIXML_SSCANF sscanf
98#endif
99
100
Lee Thomasone4422302012-01-20 17:59:50 -0800101static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800102static const char LF = LINE_FEED;
103static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
104static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800105static const char SINGLE_QUOTE = '\'';
106static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800107
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800108// Bunch of unicode info at:
109// http://www.unicode.org/faq/utf_bom.html
110// ef bb bf (Microsoft "lead bytes") - designates UTF-8
111
112static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
113static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
114static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800115
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800116namespace tinyxml2
117{
118
Lee Thomason8ee79892012-01-25 17:44:30 -0800119struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 const char* pattern;
121 int length;
122 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800123};
124
125static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126static const Entity entities[NUM_ENTITIES] = {
127 { "quot", 4, DOUBLE_QUOTE },
128 { "amp", 3, '&' },
129 { "apos", 4, SINGLE_QUOTE },
130 { "lt", 2, '<' },
131 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800132};
133
Lee Thomasonfde6a752012-01-14 18:08:12 -0800134
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135StrPair::~StrPair()
136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700137 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138}
139
140
Lee Thomason29658802014-11-27 22:31:11 -0800141void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300142{
Lee Thomason29658802014-11-27 22:31:11 -0800143 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300144 return;
145 }
146 // This in effect implements the assignment operator by "moving"
147 // ownership (as in auto_ptr).
148
Lee Thomason29658802014-11-27 22:31:11 -0800149 TIXMLASSERT( other->_flags == 0 );
150 TIXMLASSERT( other->_start == 0 );
151 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300152
Lee Thomason29658802014-11-27 22:31:11 -0800153 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300154
Lee Thomason29658802014-11-27 22:31:11 -0800155 other->_flags = _flags;
156 other->_start = _start;
157 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
159 _flags = 0;
160 _start = 0;
161 _end = 0;
162}
163
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800164void StrPair::Reset()
165{
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 if ( _flags & NEEDS_DELETE ) {
167 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700168 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700169 _flags = 0;
170 _start = 0;
171 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800172}
173
174
175void StrPair::SetStr( const char* str, int flags )
176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700177 Reset();
178 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700179 _start = new char[ len+1 ];
180 memcpy( _start, str, len+1 );
181 _end = _start + len;
182 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800183}
184
185
186char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700188 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400190 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700191 char endChar = *endTag;
192 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 // Inner loop of text parsing.
195 while ( *p ) {
196 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
197 Set( start, p, strFlags );
198 return p + length;
199 }
200 ++p;
201 }
202 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800203}
204
205
206char* StrPair::ParseName( char* p )
207{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400208 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 return 0;
210 }
JayXonee525db2014-12-24 04:01:42 -0500211 if ( !XMLUtil::IsNameStartChar( *p ) ) {
212 return 0;
213 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400215 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500216 ++p;
217 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700218 ++p;
219 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800220
JayXonee525db2014-12-24 04:01:42 -0500221 Set( start, p, 0 );
222 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800223}
224
225
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700226void StrPair::CollapseWhitespace()
227{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400228 // Adjusting _start would cause undefined behavior on delete[]
229 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700231 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700232
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300233 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700234 char* p = _start; // the read pointer
235 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700236
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700237 while( *p ) {
238 if ( XMLUtil::IsWhiteSpace( *p )) {
239 p = XMLUtil::SkipWhiteSpace( p );
240 if ( *p == 0 ) {
241 break; // don't write to q; this trims the trailing space.
242 }
243 *q = ' ';
244 ++q;
245 }
246 *q = *p;
247 ++q;
248 ++p;
249 }
250 *q = 0;
251 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700252}
253
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800254
Lee Thomasone4422302012-01-20 17:59:50 -0800255const char* StrPair::GetStr()
256{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300257 TIXMLASSERT( _start );
258 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 if ( _flags & NEEDS_FLUSH ) {
260 *_end = 0;
261 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800262
Lee Thomason120b3a62012-10-12 10:06:59 -0700263 if ( _flags ) {
264 char* p = _start; // the read pointer
265 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800266
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 while( p < _end ) {
268 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 // CR-LF pair becomes LF
270 // CR alone becomes LF
271 // LF-CR becomes LF
272 if ( *(p+1) == LF ) {
273 p += 2;
274 }
275 else {
276 ++p;
277 }
278 *q++ = LF;
279 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700280 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 if ( *(p+1) == CR ) {
282 p += 2;
283 }
284 else {
285 ++p;
286 }
287 *q++ = LF;
288 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700289 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700290 // Entities handled by tinyXML2:
291 // - special entities in the entity table [in/out]
292 // - numeric character reference [in]
293 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800294
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400296 const int buflen = 10;
297 char buf[buflen] = { 0 };
298 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300299 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
300 if ( adjusted == 0 ) {
301 *q = *p;
302 ++p;
303 ++q;
304 }
305 else {
306 TIXMLASSERT( 0 <= len && len <= buflen );
307 TIXMLASSERT( q + len <= adjusted );
308 p = adjusted;
309 memcpy( q, buf, len );
310 q += len;
311 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700312 }
313 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300314 bool entityFound = false;
315 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400316 const Entity& entity = entities[i];
317 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
318 && *( p + entity.length + 1 ) == ';' ) {
319 // Found an entity - convert.
320 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700321 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400322 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300323 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 break;
325 }
326 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 // fixme: treat as error?
329 ++p;
330 ++q;
331 }
332 }
333 }
334 else {
335 *q = *p;
336 ++p;
337 ++q;
338 }
339 }
340 *q = 0;
341 }
342 // The loop below has plenty going on, and this
343 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300344 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700345 CollapseWhitespace();
346 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700347 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700348 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300349 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700350 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800351}
352
Lee Thomason2c85a712012-01-31 08:24:24 -0800353
Lee Thomasone4422302012-01-20 17:59:50 -0800354
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800355
Lee Thomason56bdd022012-02-09 18:16:58 -0800356// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800357
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800358const char* XMLUtil::ReadBOM( const char* p, bool* bom )
359{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300360 TIXMLASSERT( p );
361 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 *bom = false;
363 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
364 // Check for BOM:
365 if ( *(pu+0) == TIXML_UTF_LEAD_0
366 && *(pu+1) == TIXML_UTF_LEAD_1
367 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
368 *bom = true;
369 p += 3;
370 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300371 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800373}
374
375
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800376void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 const unsigned long BYTE_MASK = 0xBF;
379 const unsigned long BYTE_MARK = 0x80;
380 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if (input < 0x80) {
383 *length = 1;
384 }
385 else if ( input < 0x800 ) {
386 *length = 2;
387 }
388 else if ( input < 0x10000 ) {
389 *length = 3;
390 }
391 else if ( input < 0x200000 ) {
392 *length = 4;
393 }
394 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300395 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 return;
397 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700401 // Scary scary fall throughs.
402 switch (*length) {
403 case 4:
404 --output;
405 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
406 input >>= 6;
407 case 3:
408 --output;
409 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
410 input >>= 6;
411 case 2:
412 --output;
413 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
414 input >>= 6;
415 case 1:
416 --output;
417 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100418 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300419 default:
420 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800422}
423
424
425const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Presume an entity, and pull it out.
428 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800429
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 if ( *(p+1) == '#' && *(p+2) ) {
431 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300432 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 ptrdiff_t delta = 0;
434 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800435 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800436
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 if ( *(p+2) == 'x' ) {
438 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300439 const char* q = p+3;
440 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 return 0;
442 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800443
Lee Thomason7e67bc82015-01-12 14:05:12 -0800444 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800445
Dmitry-Me9f56e122015-01-12 10:07:54 +0300446 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 return 0;
448 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800449 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800450
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 delta = q-p;
452 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700455 unsigned int digit = 0;
456
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300458 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 }
460 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300461 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 }
463 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300464 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 }
466 else {
467 return 0;
468 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300469 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300470 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
471 const unsigned int digitScaled = mult * digit;
472 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
473 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300474 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 mult *= 16;
476 --q;
477 }
478 }
479 else {
480 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300481 const char* q = p+2;
482 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 return 0;
484 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800485
Lee Thomason7e67bc82015-01-12 14:05:12 -0800486 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800487
Dmitry-Me9f56e122015-01-12 10:07:54 +0300488 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 return 0;
490 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800491 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800492
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 delta = q-p;
494 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 while ( *q != '#' ) {
497 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300498 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300499 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300500 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
501 const unsigned int digitScaled = mult * digit;
502 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
503 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 }
505 else {
506 return 0;
507 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300508 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 mult *= 10;
510 --q;
511 }
512 }
513 // convert the UCS to UTF-8
514 ConvertUTF32ToUTF8( ucs, value, length );
515 return p + delta + 1;
516 }
517 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800519
520
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700521void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700524}
525
526
527void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700530}
531
532
533void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700536}
537
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800538/*
539 ToStr() of a number is a very tricky topic.
540 https://github.com/leethomason/tinyxml2/issues/106
541*/
Lee Thomason21be8822012-07-15 17:27:22 -0700542void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
543{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800544 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700545}
546
547
548void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
549{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700551}
552
553
554bool XMLUtil::ToInt( const char* str, int* value )
555{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
557 return true;
558 }
559 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700560}
561
562bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
563{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
565 return true;
566 }
567 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700568}
569
570bool XMLUtil::ToBool( const char* str, bool* value )
571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 int ival = 0;
573 if ( ToInt( str, &ival )) {
574 *value = (ival==0) ? false : true;
575 return true;
576 }
577 if ( StringEqual( str, "true" ) ) {
578 *value = true;
579 return true;
580 }
581 else if ( StringEqual( str, "false" ) ) {
582 *value = false;
583 return true;
584 }
585 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700586}
587
588
589bool XMLUtil::ToFloat( const char* str, float* value )
590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
592 return true;
593 }
594 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700595}
596
597bool XMLUtil::ToDouble( const char* str, double* value )
598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700606char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800607{
Dmitry-Me02384662015-03-03 16:02:13 +0300608 TIXMLASSERT( node );
609 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400610 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300612 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300613 *node = 0;
614 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 return p;
616 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800617
Dmitry-Me962083b2015-05-26 11:38:30 +0300618 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 static const char* xmlHeader = { "<?" };
620 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300622 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800624
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 static const int xmlHeaderLen = 2;
626 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300628 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800630
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
632 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400633 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300635 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
637 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 p += xmlHeaderLen;
639 }
640 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300641 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 returnNode = new (_commentPool.Alloc()) XMLComment( this );
643 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 p += commentHeaderLen;
645 }
646 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300647 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 p += cdataHeaderLen;
652 text->SetCData( true );
653 }
654 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300655 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
657 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 p += dtdHeaderLen;
659 }
660 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300661 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 returnNode = new (_elementPool.Alloc()) XMLElement( this );
663 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 p += elementHeaderLen;
665 }
666 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300667 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 returnNode = new (_textPool.Alloc()) XMLText( this );
669 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 p = start; // Back it up, all the text counts.
671 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800672
Dmitry-Me02384662015-03-03 16:02:13 +0300673 TIXMLASSERT( returnNode );
674 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 *node = returnNode;
676 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677}
678
679
Lee Thomason751da522012-02-10 08:50:51 -0800680bool XMLDocument::Accept( XMLVisitor* visitor ) const
681{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300682 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 if ( visitor->VisitEnter( *this ) ) {
684 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
685 if ( !node->Accept( visitor ) ) {
686 break;
687 }
688 }
689 }
690 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800691}
Lee Thomason56bdd022012-02-09 18:16:58 -0800692
693
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800694// --------- XMLNode ----------- //
695
696XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 _document( doc ),
698 _parent( 0 ),
699 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200700 _prev( 0 ), _next( 0 ),
701 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703}
704
705
706XMLNode::~XMLNode()
707{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 if ( _parent ) {
710 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800712}
713
Michael Daumling21626882013-10-22 17:03:37 +0200714const char* XMLNode::Value() const
715{
Lee Thomason85492022015-05-22 11:07:45 -0700716 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530717 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530718 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200719 return _value.GetStr();
720}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800721
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800722void XMLNode::SetValue( const char* str, bool staticMem )
723{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
727 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800730}
731
732
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800733void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800734{
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300736 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300737 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700740
Dmitry-Mee3225b12014-09-03 11:03:11 +0400741 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700742 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800744}
745
746
747void XMLNode::Unlink( XMLNode* child )
748{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300749 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300750 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300751 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( child == _firstChild ) {
753 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 if ( child == _lastChild ) {
756 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
Lee Thomasond923c672012-01-23 08:44:25 -0800758
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 if ( child->_prev ) {
760 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 if ( child->_next ) {
763 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700765 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800766}
767
768
U-Stream\Leeae25a442012-02-17 17:48:16 -0800769void XMLNode::DeleteChild( XMLNode* node )
770{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300771 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300772 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400774 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800775}
776
777
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800778XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
779{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300780 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300781 if ( addThis->_document != _document ) {
782 TIXMLASSERT( false );
783 return 0;
784 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800785 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700786
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 if ( _lastChild ) {
788 TIXMLASSERT( _firstChild );
789 TIXMLASSERT( _lastChild->_next == 0 );
790 _lastChild->_next = addThis;
791 addThis->_prev = _lastChild;
792 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800793
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 }
796 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 TIXMLASSERT( _firstChild == 0 );
798 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800799
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 addThis->_prev = 0;
801 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805}
806
807
Lee Thomason1ff38e02012-02-14 18:18:16 -0800808XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
809{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300810 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300811 if ( addThis->_document != _document ) {
812 TIXMLASSERT( false );
813 return 0;
814 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800815 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700816
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 if ( _firstChild ) {
818 TIXMLASSERT( _lastChild );
819 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 _firstChild->_prev = addThis;
822 addThis->_next = _firstChild;
823 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800824
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 }
827 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 TIXMLASSERT( _lastChild == 0 );
829 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 addThis->_prev = 0;
832 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400835 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800836}
837
838
839XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
840{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300841 TIXMLASSERT( addThis );
842 if ( addThis->_document != _document ) {
843 TIXMLASSERT( false );
844 return 0;
845 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700846
Dmitry-Meabb2d042014-12-09 12:59:31 +0300847 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300850 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 return 0;
852 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800853
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 // The last node or the only node.
856 return InsertEndChild( addThis );
857 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800858 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 addThis->_prev = afterThis;
860 addThis->_next = afterThis->_next;
861 afterThis->_next->_prev = addThis;
862 afterThis->_next = addThis;
863 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800865}
866
867
868
869
Dmitry-Me886ad972015-07-22 11:00:51 +0300870const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800871{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300872 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
873 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300875 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 return element;
877 }
878 }
879 }
880 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800881}
882
883
Dmitry-Me886ad972015-07-22 11:00:51 +0300884const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800885{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300886 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
887 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300889 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 return element;
891 }
892 }
893 }
894 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800895}
896
897
Dmitry-Me886ad972015-07-22 11:00:51 +0300898const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800899{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300900 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400901 const XMLElement* element = node->ToElement();
902 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300903 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400904 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 }
906 }
907 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800908}
909
910
Dmitry-Me886ad972015-07-22 11:00:51 +0300911const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800912{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300913 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400914 const XMLElement* element = node->ToElement();
915 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300916 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400917 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
919 }
920 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800921}
922
923
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800924char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800925{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 // This is a recursive method, but thinking about it "at the current level"
927 // it is a pretty simple flat list:
928 // <foo/>
929 // <!-- comment -->
930 //
931 // With a special case:
932 // <foo>
933 // </foo>
934 // <!-- comment -->
935 //
936 // Where the closing element (/foo) *must* be the next thing after the opening
937 // element, and the names must match. BUT the tricky bit is that the closing
938 // element will be read by the child.
939 //
940 // 'endTag' is the end tag for this node, it is returned by a call to a child.
941 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800942
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 while( p && *p ) {
944 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800945
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300947 if ( node == 0 ) {
948 break;
949 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 StrPair endTag;
952 p = node->ParseDeep( p, &endTag );
953 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400954 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 if ( !_document->Error() ) {
956 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 break;
959 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800960
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530961 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530962 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530963 // A declaration can only be the first child of a document.
964 // Set error, if document already has children.
965 if ( !_document->NoChildren() ) {
966 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
967 DeleteNode( decl );
968 break;
969 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530970 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530971
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400972 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500974 // We read the end tag. Return it to the parent.
975 if ( ele->ClosingType() == XMLElement::CLOSING ) {
976 if ( parentEnd ) {
977 ele->_value.TransferTo( parentEnd );
978 }
979 node->_memPool->SetTracked(); // created and then immediately deleted.
980 DeleteNode( node );
981 return p;
982 }
983
984 // Handle an end tag returned to this level.
985 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400986 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300987 if ( endTag.Empty() ) {
988 if ( ele->ClosingType() == XMLElement::OPEN ) {
989 mismatch = true;
990 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300992 else {
993 if ( ele->ClosingType() != XMLElement::OPEN ) {
994 mismatch = true;
995 }
Dmitry-Me886ad972015-07-22 11:00:51 +0300996 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400997 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 }
999 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001000 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001001 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001002 DeleteNode( node );
1003 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001004 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 }
JayXondbfdd8f2014-12-12 20:07:14 -05001006 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 }
1008 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001009}
1010
Dmitry-Mee3225b12014-09-03 11:03:11 +04001011void XMLNode::DeleteNode( XMLNode* node )
1012{
1013 if ( node == 0 ) {
1014 return;
1015 }
1016 MemPool* pool = node->_memPool;
1017 node->~XMLNode();
1018 pool->Free( node );
1019}
1020
Lee Thomason3cebdc42015-01-05 17:16:28 -08001021void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001022{
1023 TIXMLASSERT( insertThis );
1024 TIXMLASSERT( insertThis->_document == _document );
1025
1026 if ( insertThis->_parent )
1027 insertThis->_parent->Unlink( insertThis );
1028 else
1029 insertThis->_memPool->SetTracked();
1030}
1031
Lee Thomason5492a1c2012-01-23 15:32:10 -08001032// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 const char* start = p;
1036 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 return p;
1042 }
1043 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1045 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001046 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001048
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( p && *p ) {
1051 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001052 }
1053 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001054 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 }
1056 }
1057 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001058}
1059
1060
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001061XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 }
1066 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1067 text->SetCData( this->CData() );
1068 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001069}
1070
1071
1072bool XMLText::ShallowEqual( const XMLNode* compare ) const
1073{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001074 const XMLText* text = compare->ToText();
1075 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001076}
1077
1078
Lee Thomason56bdd022012-02-09 18:16:58 -08001079bool XMLText::Accept( XMLVisitor* visitor ) const
1080{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001081 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001083}
1084
1085
Lee Thomason3f57d272012-01-11 15:30:03 -08001086// --------- XMLComment ---------- //
1087
Lee Thomasone4422302012-01-20 17:59:50 -08001088XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001089{
1090}
1091
1092
Lee Thomasonce0763e2012-01-11 15:43:54 -08001093XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001094{
Lee Thomason3f57d272012-01-11 15:30:03 -08001095}
1096
1097
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001098char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 // Comment parses as text.
1101 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001102 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001104 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 }
1106 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001107}
1108
1109
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001113 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 }
1115 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1116 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001117}
1118
1119
1120bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1121{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001122 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001123 const XMLComment* comment = compare->ToComment();
1124 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001125}
1126
1127
Lee Thomason751da522012-02-10 08:50:51 -08001128bool XMLComment::Accept( XMLVisitor* visitor ) const
1129{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001130 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001132}
Lee Thomason56bdd022012-02-09 18:16:58 -08001133
1134
Lee Thomason50f97b22012-02-11 16:33:40 -08001135// --------- XMLDeclaration ---------- //
1136
1137XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1138{
1139}
1140
1141
1142XMLDeclaration::~XMLDeclaration()
1143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001145}
1146
1147
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001148char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 // Declaration parses as text.
1151 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001154 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 }
1156 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001157}
1158
1159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 }
1165 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1166 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001167}
1168
1169
1170bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1171{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001172 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001173 const XMLDeclaration* declaration = compare->ToDeclaration();
1174 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001175}
1176
1177
1178
Lee Thomason50f97b22012-02-11 16:33:40 -08001179bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1180{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001181 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001183}
1184
1185// --------- XMLUnknown ---------- //
1186
1187XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1188{
1189}
1190
1191
1192XMLUnknown::~XMLUnknown()
1193{
1194}
1195
1196
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001197char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 // Unknown parses as text.
1200 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001201
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001204 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 }
1206 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001207}
1208
1209
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
1215 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1216 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217}
1218
1219
1220bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1221{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001222 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001223 const XMLUnknown* unknown = compare->ToUnknown();
1224 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001225}
1226
1227
Lee Thomason50f97b22012-02-11 16:33:40 -08001228bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1229{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001230 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001232}
1233
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001234// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001235
1236const char* XMLAttribute::Name() const
1237{
1238 return _name.GetStr();
1239}
1240
1241const char* XMLAttribute::Value() const
1242{
1243 return _value.GetStr();
1244}
1245
Lee Thomason6f381b72012-03-02 12:59:39 -08001246char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001249 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 if ( !p || !*p ) {
1251 return 0;
1252 }
Lee Thomason22aead12012-01-23 13:29:35 -08001253
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 // Skip white space before =
1255 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001256 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 return 0;
1258 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001259
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 ++p; // move up to opening quote
1261 p = XMLUtil::SkipWhiteSpace( p );
1262 if ( *p != '\"' && *p != '\'' ) {
1263 return 0;
1264 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001265
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 char endTag[2] = { *p, 0 };
1267 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001268
Lee Thomason624d43f2012-10-12 10:58:48 -07001269 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001271}
1272
1273
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001274void XMLAttribute::SetName( const char* n )
1275{
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001277}
1278
1279
Lee Thomason2fa81722012-11-09 12:37:46 -08001280XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 if ( XMLUtil::ToInt( Value(), value )) {
1283 return XML_NO_ERROR;
1284 }
1285 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001286}
1287
1288
Lee Thomason2fa81722012-11-09 12:37:46 -08001289XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 if ( XMLUtil::ToUnsigned( Value(), value )) {
1292 return XML_NO_ERROR;
1293 }
1294 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001295}
1296
1297
Lee Thomason2fa81722012-11-09 12:37:46 -08001298XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 if ( XMLUtil::ToBool( Value(), value )) {
1301 return XML_NO_ERROR;
1302 }
1303 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001304}
1305
1306
Lee Thomason2fa81722012-11-09 12:37:46 -08001307XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( XMLUtil::ToFloat( Value(), value )) {
1310 return XML_NO_ERROR;
1311 }
1312 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001313}
1314
1315
Lee Thomason2fa81722012-11-09 12:37:46 -08001316XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( XMLUtil::ToDouble( Value(), value )) {
1319 return XML_NO_ERROR;
1320 }
1321 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001322}
1323
1324
1325void XMLAttribute::SetAttribute( const char* v )
1326{
Lee Thomason624d43f2012-10-12 10:58:48 -07001327 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001328}
1329
1330
Lee Thomason1ff38e02012-02-14 18:18:16 -08001331void XMLAttribute::SetAttribute( int v )
1332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 char buf[BUF_SIZE];
1334 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001335 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001336}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001337
1338
1339void XMLAttribute::SetAttribute( unsigned v )
1340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 char buf[BUF_SIZE];
1342 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001343 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001344}
1345
1346
1347void XMLAttribute::SetAttribute( bool v )
1348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 char buf[BUF_SIZE];
1350 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001351 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001352}
1353
1354void XMLAttribute::SetAttribute( double v )
1355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 char buf[BUF_SIZE];
1357 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001358 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001359}
1360
1361void XMLAttribute::SetAttribute( float v )
1362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 char buf[BUF_SIZE];
1364 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001365 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001366}
1367
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001368
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001369// --------- XMLElement ---------- //
1370XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _closingType( 0 ),
1372 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001373{
1374}
1375
1376
1377XMLElement::~XMLElement()
1378{
Lee Thomason624d43f2012-10-12 10:58:48 -07001379 while( _rootAttribute ) {
1380 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001381 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001382 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001384}
1385
1386
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001387const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1388{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001389 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1391 return a;
1392 }
1393 }
1394 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001395}
1396
1397
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001398const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001399{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 const XMLAttribute* a = FindAttribute( name );
1401 if ( !a ) {
1402 return 0;
1403 }
1404 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1405 return a->Value();
1406 }
1407 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001408}
1409
1410
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001411const char* XMLElement::GetText() const
1412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001414 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 }
1416 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001417}
1418
1419
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001420void XMLElement::SetText( const char* inText )
1421{
Uli Kusterer869bb592014-01-21 01:36:16 +01001422 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001423 FirstChild()->SetValue( inText );
1424 else {
1425 XMLText* theText = GetDocument()->NewText( inText );
1426 InsertFirstChild( theText );
1427 }
1428}
1429
Lee Thomason5bb2d802014-01-24 10:42:57 -08001430
1431void XMLElement::SetText( int v )
1432{
1433 char buf[BUF_SIZE];
1434 XMLUtil::ToStr( v, buf, BUF_SIZE );
1435 SetText( buf );
1436}
1437
1438
1439void XMLElement::SetText( unsigned v )
1440{
1441 char buf[BUF_SIZE];
1442 XMLUtil::ToStr( v, buf, BUF_SIZE );
1443 SetText( buf );
1444}
1445
1446
1447void XMLElement::SetText( bool v )
1448{
1449 char buf[BUF_SIZE];
1450 XMLUtil::ToStr( v, buf, BUF_SIZE );
1451 SetText( buf );
1452}
1453
1454
1455void XMLElement::SetText( float v )
1456{
1457 char buf[BUF_SIZE];
1458 XMLUtil::ToStr( v, buf, BUF_SIZE );
1459 SetText( buf );
1460}
1461
1462
1463void XMLElement::SetText( double v )
1464{
1465 char buf[BUF_SIZE];
1466 XMLUtil::ToStr( v, buf, BUF_SIZE );
1467 SetText( buf );
1468}
1469
1470
MortenMacFly4ee49f12013-01-14 20:03:14 +01001471XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001474 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001475 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 return XML_SUCCESS;
1477 }
1478 return XML_CAN_NOT_CONVERT_TEXT;
1479 }
1480 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001481}
1482
1483
MortenMacFly4ee49f12013-01-14 20:03:14 +01001484XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001487 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001488 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 return XML_SUCCESS;
1490 }
1491 return XML_CAN_NOT_CONVERT_TEXT;
1492 }
1493 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001494}
1495
1496
MortenMacFly4ee49f12013-01-14 20:03:14 +01001497XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001498{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001500 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001501 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 return XML_SUCCESS;
1503 }
1504 return XML_CAN_NOT_CONVERT_TEXT;
1505 }
1506 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001507}
1508
1509
MortenMacFly4ee49f12013-01-14 20:03:14 +01001510XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001511{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001513 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001514 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 return XML_SUCCESS;
1516 }
1517 return XML_CAN_NOT_CONVERT_TEXT;
1518 }
1519 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001520}
1521
1522
MortenMacFly4ee49f12013-01-14 20:03:14 +01001523XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001526 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001527 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 return XML_SUCCESS;
1529 }
1530 return XML_CAN_NOT_CONVERT_TEXT;
1531 }
1532 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001533}
1534
1535
1536
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001537XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 XMLAttribute* last = 0;
1540 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001543 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1545 break;
1546 }
1547 }
1548 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001549 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1551 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 }
1555 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 }
1558 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001559 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 }
1561 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001562}
1563
1564
U-Stream\Leeae25a442012-02-17 17:48:16 -08001565void XMLElement::DeleteAttribute( const char* name )
1566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1570 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001571 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 }
1573 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001576 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 break;
1578 }
1579 prev = a;
1580 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001581}
1582
1583
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001584char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001585{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 const char* start = p;
1587 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001588
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 // Read the attributes.
1590 while( p ) {
1591 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001592 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001593 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 return 0;
1595 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001596
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001598 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001599 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001600 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1601 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001602 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001603
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001606 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 return 0;
1609 }
1610 // There is a minor bug here: if the attribute in the source xml
1611 // document is duplicated, it will not be detected and the
1612 // attribute will be doubly added. However, tracking the 'prevAttribute'
1613 // avoids re-scanning the attribute list. Preferring performance for
1614 // now, may reconsider in the future.
1615 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 }
1618 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
1621 prevAttribute = attrib;
1622 }
1623 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 else if ( *p == '>' ) {
1625 ++p;
1626 break;
1627 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001628 // end of the tag
1629 else if ( *p == '/' && *(p+1) == '>' ) {
1630 _closingType = CLOSED;
1631 return p+2; // done; sealed element.
1632 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 return 0;
1636 }
1637 }
1638 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001639}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001640
Dmitry-Mee3225b12014-09-03 11:03:11 +04001641void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1642{
1643 if ( attribute == 0 ) {
1644 return;
1645 }
1646 MemPool* pool = attribute->_memPool;
1647 attribute->~XMLAttribute();
1648 pool->Free( attribute );
1649}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001650
Lee Thomason67d61312012-01-24 16:01:51 -08001651//
1652// <ele></ele>
1653// <ele>foo<b>bar</b></ele>
1654//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001655char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 // Read the element name.
1658 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001659
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 // The closing element is the </element> form. It is
1661 // parsed just like a regular element then deleted from
1662 // the DOM.
1663 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 ++p;
1666 }
Lee Thomason67d61312012-01-24 16:01:51 -08001667
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 p = _value.ParseName( p );
1669 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return 0;
1671 }
Lee Thomason67d61312012-01-24 16:01:51 -08001672
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001674 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001675 return p;
1676 }
Lee Thomason67d61312012-01-24 16:01:51 -08001677
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 p = XMLNode::ParseDeep( p, strPair );
1679 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001680}
1681
1682
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001683
1684XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1685{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 }
1689 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1690 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1691 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1692 }
1693 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001694}
1695
1696
1697bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1698{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001699 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001701 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001702
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 const XMLAttribute* a=FirstAttribute();
1704 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001705
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 while ( a && b ) {
1707 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1708 return false;
1709 }
1710 a = a->Next();
1711 b = b->Next();
1712 }
1713 if ( a || b ) {
1714 // different count
1715 return false;
1716 }
1717 return true;
1718 }
1719 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001720}
1721
1722
Lee Thomason751da522012-02-10 08:50:51 -08001723bool XMLElement::Accept( XMLVisitor* visitor ) const
1724{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001725 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1728 if ( !node->Accept( visitor ) ) {
1729 break;
1730 }
1731 }
1732 }
1733 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001734}
Lee Thomason56bdd022012-02-09 18:16:58 -08001735
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001736
Lee Thomason3f57d272012-01-11 15:30:03 -08001737// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001738
1739// Warning: List must match 'enum XMLError'
1740const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1741 "XML_SUCCESS",
1742 "XML_NO_ATTRIBUTE",
1743 "XML_WRONG_ATTRIBUTE_TYPE",
1744 "XML_ERROR_FILE_NOT_FOUND",
1745 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1746 "XML_ERROR_FILE_READ_ERROR",
1747 "XML_ERROR_ELEMENT_MISMATCH",
1748 "XML_ERROR_PARSING_ELEMENT",
1749 "XML_ERROR_PARSING_ATTRIBUTE",
1750 "XML_ERROR_IDENTIFYING_TAG",
1751 "XML_ERROR_PARSING_TEXT",
1752 "XML_ERROR_PARSING_CDATA",
1753 "XML_ERROR_PARSING_COMMENT",
1754 "XML_ERROR_PARSING_DECLARATION",
1755 "XML_ERROR_PARSING_UNKNOWN",
1756 "XML_ERROR_EMPTY_DOCUMENT",
1757 "XML_ERROR_MISMATCHED_ELEMENT",
1758 "XML_ERROR_PARSING",
1759 "XML_CAN_NOT_CONVERT_TEXT",
1760 "XML_NO_TEXT_NODE"
1761};
1762
1763
Lee Thomason624d43f2012-10-12 10:58:48 -07001764XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 _writeBOM( false ),
1767 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001768 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 _whitespace( whitespace ),
1770 _errorStr1( 0 ),
1771 _errorStr2( 0 ),
1772 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001773{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001774 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1775 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001776}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001777
1778
Lee Thomason3f57d272012-01-11 15:30:03 -08001779XMLDocument::~XMLDocument()
1780{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001781 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001782}
1783
1784
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001785void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001786{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001787 DeleteChildren();
1788
Dmitry-Meab37df82014-11-28 12:08:36 +03001789#ifdef DEBUG
1790 const bool hadError = Error();
1791#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 _errorID = XML_NO_ERROR;
1793 _errorStr1 = 0;
1794 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001795
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 delete [] _charBuffer;
1797 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001798
1799#if 0
1800 _textPool.Trace( "text" );
1801 _elementPool.Trace( "element" );
1802 _commentPool.Trace( "comment" );
1803 _attributePool.Trace( "attribute" );
1804#endif
1805
1806#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001807 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001808 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1809 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1810 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1811 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1812 }
1813#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001814}
1815
Lee Thomason3f57d272012-01-11 15:30:03 -08001816
Lee Thomason2c85a712012-01-31 08:24:24 -08001817XMLElement* XMLDocument::NewElement( const char* name )
1818{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001819 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1821 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 ele->SetName( name );
1823 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001824}
1825
1826
Lee Thomason1ff38e02012-02-14 18:18:16 -08001827XMLComment* XMLDocument::NewComment( const char* str )
1828{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001829 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1831 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 comment->SetValue( str );
1833 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001834}
1835
1836
1837XMLText* XMLDocument::NewText( const char* str )
1838{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001839 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1841 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 text->SetValue( str );
1843 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001844}
1845
1846
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001847XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1848{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001849 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1851 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1853 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001854}
1855
1856
1857XMLUnknown* XMLDocument::NewUnknown( const char* str )
1858{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001859 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1861 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 unk->SetValue( str );
1863 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001864}
1865
Dmitry-Me01578db2014-08-19 10:18:48 +04001866static FILE* callfopen( const char* filepath, const char* mode )
1867{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001868 TIXMLASSERT( filepath );
1869 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001870#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1871 FILE* fp = 0;
1872 errno_t err = fopen_s( &fp, filepath, mode );
1873 if ( err ) {
1874 return 0;
1875 }
1876#else
1877 FILE* fp = fopen( filepath, mode );
1878#endif
1879 return fp;
1880}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001881
1882void XMLDocument::DeleteNode( XMLNode* node ) {
1883 TIXMLASSERT( node );
1884 TIXMLASSERT(node->_document == this );
1885 if (node->_parent) {
1886 node->_parent->DeleteChild( node );
1887 }
1888 else {
1889 // Isn't in the tree.
1890 // Use the parent delete.
1891 // Also, we need to mark it tracked: we 'know'
1892 // it was never used.
1893 node->_memPool->SetTracked();
1894 // Call the static XMLNode version:
1895 XMLNode::DeleteNode(node);
1896 }
1897}
1898
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001899
Lee Thomason2fa81722012-11-09 12:37:46 -08001900XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001901{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001902 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001903 FILE* fp = callfopen( filename, "rb" );
1904 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 }
1908 LoadFile( fp );
1909 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001911}
1912
1913
Lee Thomason2fa81722012-11-09 12:37:46 -08001914XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001915{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001916 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001917
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001918 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001919 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001920 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1921 return _errorID;
1922 }
1923
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001925 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001927 if ( filelength == -1L ) {
1928 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1929 return _errorID;
1930 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001931
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001932 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001933 // Cannot handle files which won't fit in buffer together with null terminator
1934 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1935 return _errorID;
1936 }
1937
Dmitry-Me72801b82015-05-07 09:41:39 +03001938 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001939 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001942
Dmitry-Me72801b82015-05-07 09:41:39 +03001943 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 _charBuffer = new char[size+1];
1945 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 if ( read != size ) {
1947 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001952
Dmitry-Me97476b72015-01-01 16:15:57 +03001953 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955}
1956
1957
Lee Thomason2fa81722012-11-09 12:37:46 -08001958XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001959{
Dmitry-Me01578db2014-08-19 10:18:48 +04001960 FILE* fp = callfopen( filename, "w" );
1961 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 }
1965 SaveFile(fp, compact);
1966 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001968}
1969
1970
Lee Thomason2fa81722012-11-09 12:37:46 -08001971XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001972{
Ant Mitchell189198f2015-03-24 16:20:36 +00001973 // Clear any error from the last save, otherwise it will get reported
1974 // for *this* call.
1975 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 XMLPrinter stream( fp, compact );
1977 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001979}
1980
Lee Thomason1ff38e02012-02-14 18:18:16 -08001981
Lee Thomason2fa81722012-11-09 12:37:46 -08001982XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001983{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001984 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001985
Lee Thomason82d32002014-02-21 22:47:18 -08001986 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 }
1990 if ( len == (size_t)(-1) ) {
1991 len = strlen( p );
1992 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 _charBuffer = new char[ len+1 ];
1994 memcpy( _charBuffer, p, len );
1995 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001996
Dmitry-Me97476b72015-01-01 16:15:57 +03001997 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001998 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001999 // clean up now essentially dangling memory.
2000 // and the parse fail can put objects in the
2001 // pools that are dead and inaccessible.
2002 DeleteChildren();
2003 _elementPool.Clear();
2004 _attributePool.Clear();
2005 _textPool.Clear();
2006 _commentPool.Clear();
2007 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002009}
2010
2011
PKEuS1c5f99e2013-07-06 11:28:39 +02002012void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002013{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002014 if ( streamer ) {
2015 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002017 else {
2018 XMLPrinter stdoutStreamer( stdout );
2019 Accept( &stdoutStreamer );
2020 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002021}
2022
2023
Lee Thomason2fa81722012-11-09 12:37:46 -08002024void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002025{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002026 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _errorID = error;
2028 _errorStr1 = str1;
2029 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002030}
2031
Lee Thomason331596e2014-09-11 14:56:43 -07002032const char* XMLDocument::ErrorName() const
2033{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002034 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002035 const char* errorName = _errorNames[_errorID];
2036 TIXMLASSERT( errorName && errorName[0] );
2037 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002038}
Lee Thomason5cae8972012-01-24 18:03:07 -08002039
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002040void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002041{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002042 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 static const int LEN = 20;
2044 char buf1[LEN] = { 0 };
2045 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002046
Lee Thomason624d43f2012-10-12 10:58:48 -07002047 if ( _errorStr1 ) {
2048 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 if ( _errorStr2 ) {
2051 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002053
Dmitry-Me2ad43202015-04-16 12:18:58 +03002054 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2055 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2056 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002057 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002058 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002060}
2061
Dmitry-Me97476b72015-01-01 16:15:57 +03002062void XMLDocument::Parse()
2063{
2064 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2065 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002066 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002067 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002068 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002069 if ( !*p ) {
2070 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2071 return;
2072 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002073 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002074}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002075
PKEuS1bfb9542013-08-04 13:51:17 +02002076XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _elementJustOpened( false ),
2078 _firstElement( true ),
2079 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002080 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 _textDepth( -1 ),
2082 _processEntities( true ),
2083 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 _entityFlag[i] = false;
2087 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 }
2089 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002090 const char entityValue = entities[i].value;
2091 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2092 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002094 _restrictedEntityFlag[(unsigned char)'&'] = true;
2095 _restrictedEntityFlag[(unsigned char)'<'] = true;
2096 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002097 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002098}
2099
2100
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002101void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002102{
2103 va_list va;
2104 va_start( va, format );
2105
Lee Thomason624d43f2012-10-12 10:58:48 -07002106 if ( _fp ) {
2107 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 }
2109 else {
pffang1527cf42015-06-09 13:57:11 +08002110 int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 // Close out and re-start the va-args
2112 va_end( va );
2113 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002114 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002115 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002116 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002118 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002119}
2120
2121
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002122void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 for( int i=0; i<depth; ++i ) {
2125 Print( " " );
2126 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002127}
2128
2129
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002130void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 // Look for runs of bytes between entities to print.
2133 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002134
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002136 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002138 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 // Remember, char is sometimes signed. (How many times has that bitten me?)
2140 if ( *q > 0 && *q < ENTITY_RANGE ) {
2141 // Check for entities. If one is found, flush
2142 // the stream up until the entity, write the
2143 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002144 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002146 const size_t delta = q - p;
2147 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002148 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002149 Print( "%.*s", toPrint, p );
2150 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002152 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 for( int i=0; i<NUM_ENTITIES; ++i ) {
2154 if ( entities[i].value == *q ) {
2155 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002156 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 break;
2158 }
2159 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002160 if ( !entityPatternPrinted ) {
2161 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2162 TIXMLASSERT( false );
2163 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 ++p;
2165 }
2166 }
2167 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002168 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 }
2170 }
2171 // Flush the remaining string. This will be the entire
2172 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002173 TIXMLASSERT( p <= q );
2174 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 Print( "%s", p );
2176 }
Lee Thomason857b8682012-01-25 17:50:25 -08002177}
2178
U-Stream\Leeae25a442012-02-17 17:48:16 -08002179
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002180void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002183 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 -07002184 Print( "%s", bom );
2185 }
2186 if ( writeDec ) {
2187 PushDeclaration( "xml version=\"1.0\"" );
2188 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002189}
2190
2191
Uli Kusterer593a33d2014-02-01 12:48:51 +01002192void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002193{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002194 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002196
Uli Kusterer593a33d2014-02-01 12:48:51 +01002197 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002199 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002200 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002203
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 _elementJustOpened = true;
2206 _firstElement = false;
2207 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002208}
2209
2210
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002211void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002212{
Lee Thomason624d43f2012-10-12 10:58:48 -07002213 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 Print( " %s=\"", name );
2215 PrintString( value, false );
2216 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002217}
2218
2219
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002220void XMLPrinter::PushAttribute( const char* name, int v )
2221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 char buf[BUF_SIZE];
2223 XMLUtil::ToStr( v, buf, BUF_SIZE );
2224 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002225}
2226
2227
2228void XMLPrinter::PushAttribute( const char* name, unsigned v )
2229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 char buf[BUF_SIZE];
2231 XMLUtil::ToStr( v, buf, BUF_SIZE );
2232 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002233}
2234
2235
2236void XMLPrinter::PushAttribute( const char* name, bool v )
2237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 char buf[BUF_SIZE];
2239 XMLUtil::ToStr( v, buf, BUF_SIZE );
2240 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002241}
2242
2243
2244void XMLPrinter::PushAttribute( const char* name, double v )
2245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 char buf[BUF_SIZE];
2247 XMLUtil::ToStr( v, buf, BUF_SIZE );
2248 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002249}
2250
2251
Uli Kustererca412e82014-02-01 13:35:05 +01002252void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002253{
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 --_depth;
2255 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002256
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 Print( "/>" );
2259 }
2260 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002261 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
2265 Print( "</%s>", name );
2266 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002267
Lee Thomason624d43f2012-10-12 10:58:48 -07002268 if ( _textDepth == _depth ) {
2269 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 }
Uli Kustererca412e82014-02-01 13:35:05 +01002271 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 Print( "\n" );
2273 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002274 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002275}
2276
2277
Dmitry-Mea092bc12014-12-23 17:57:05 +03002278void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002279{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002280 if ( !_elementJustOpened ) {
2281 return;
2282 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002289{
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002291
Dmitry-Mea092bc12014-12-23 17:57:05 +03002292 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002294 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 }
2296 else {
2297 PrintString( text, true );
2298 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002299}
2300
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002301void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 char buf[BUF_SIZE];
2304 XMLUtil::ToStr( value, buf, BUF_SIZE );
2305 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002306}
2307
2308
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002309void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002310{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 char buf[BUF_SIZE];
2312 XMLUtil::ToStr( value, buf, BUF_SIZE );
2313 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002314}
2315
2316
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002317void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 char buf[BUF_SIZE];
2320 XMLUtil::ToStr( value, buf, BUF_SIZE );
2321 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002322}
2323
2324
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002325void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 char buf[BUF_SIZE];
2328 XMLUtil::ToStr( value, buf, BUF_SIZE );
2329 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002330}
2331
2332
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002333void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 char buf[BUF_SIZE];
2336 XMLUtil::ToStr( value, buf, BUF_SIZE );
2337 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002338}
2339
Lee Thomason5cae8972012-01-24 18:03:07 -08002340
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002341void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002342{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002343 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002344 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002346 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002348 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002350}
Lee Thomason751da522012-02-10 08:50:51 -08002351
2352
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002353void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002354{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002355 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002362}
2363
2364
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002365void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002366{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002367 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002368 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002373 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002374}
2375
2376
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002377bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002378{
Lee Thomason624d43f2012-10-12 10:58:48 -07002379 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002380 if ( doc.HasBOM() ) {
2381 PushHeader( true, false );
2382 }
2383 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002384}
2385
2386
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002387bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002388{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002389 const XMLElement* parentElem = 0;
2390 if ( element.Parent() ) {
2391 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002392 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002393 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002394 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 while ( attribute ) {
2396 PushAttribute( attribute->Name(), attribute->Value() );
2397 attribute = attribute->Next();
2398 }
2399 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002400}
2401
2402
Uli Kustererca412e82014-02-01 13:35:05 +01002403bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002404{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002405 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002407}
2408
2409
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002410bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 PushText( text.Value(), text.CData() );
2413 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002414}
2415
2416
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002417bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002419 PushComment( comment.Value() );
2420 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002421}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002422
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002423bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 PushDeclaration( declaration.Value() );
2426 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002427}
2428
2429
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002430bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002432 PushUnknown( unknown.Value() );
2433 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002434}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002435
Lee Thomason685b8952012-11-12 13:00:06 -08002436} // namespace tinyxml2
2437