blob: 4a4dec48412d73ee4b9197dae2322a0066e70e37 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
354 ptrdiff_t delta = 0;
355 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 if ( *(p+2) == 'x' ) {
358 // Hexadecimal.
359 if ( !*(p+3) ) {
360 return 0;
361 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 const char* q = p+3;
364 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 if ( !q || !*q ) {
367 return 0;
368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 delta = q-p;
371 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 while ( *q != 'x' ) {
374 if ( *q >= '0' && *q <= '9' ) {
375 ucs += mult * (*q - '0');
376 }
377 else if ( *q >= 'a' && *q <= 'f' ) {
378 ucs += mult * (*q - 'a' + 10);
379 }
380 else if ( *q >= 'A' && *q <= 'F' ) {
381 ucs += mult * (*q - 'A' + 10 );
382 }
383 else {
384 return 0;
385 }
386 mult *= 16;
387 --q;
388 }
389 }
390 else {
391 // Decimal.
392 if ( !*(p+2) ) {
393 return 0;
394 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 const char* q = p+2;
397 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 if ( !q || !*q ) {
400 return 0;
401 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 delta = q-p;
404 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 while ( *q != '#' ) {
407 if ( *q >= '0' && *q <= '9' ) {
408 ucs += mult * (*q - '0');
409 }
410 else {
411 return 0;
412 }
413 mult *= 10;
414 --q;
415 }
416 }
417 // convert the UCS to UTF-8
418 ConvertUTF32ToUTF8( ucs, value, length );
419 return p + delta + 1;
420 }
421 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800422}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800423
424
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700425void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442/*
443 ToStr() of a number is a very tricky topic.
444 https://github.com/leethomason/tinyxml2/issues/106
445*/
Lee Thomason21be8822012-07-15 17:27:22 -0700446void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458bool XMLUtil::ToInt( const char* str, int* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
461 return true;
462 }
463 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700464}
465
466bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474bool XMLUtil::ToBool( const char* str, bool* value )
475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700476 int ival = 0;
477 if ( ToInt( str, &ival )) {
478 *value = (ival==0) ? false : true;
479 return true;
480 }
481 if ( StringEqual( str, "true" ) ) {
482 *value = true;
483 return true;
484 }
485 else if ( StringEqual( str, "false" ) ) {
486 *value = false;
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
493bool XMLUtil::ToFloat( const char* str, float* value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToDouble( const char* str, double* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
504 return true;
505 }
506 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700507}
508
509
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700510char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400512 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300514 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return p;
516 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800519 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const char* xmlHeader = { "<?" };
521 static const char* commentHeader = { "<!--" };
522 static const char* dtdHeader = { "<!" };
523 static const char* cdataHeader = { "<![CDATA[" };
524 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 static const int xmlHeaderLen = 2;
527 static const int commentHeaderLen = 4;
528 static const int dtdHeaderLen = 2;
529 static const int cdataHeaderLen = 9;
530 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800531
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
533 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400534 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300536 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300542 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLComment( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += commentHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300548 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += cdataHeaderLen;
553 text->SetCData( true );
554 }
555 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300556 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300562 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700563 returnNode = new (_elementPool.Alloc()) XMLElement( this );
564 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 p += elementHeaderLen;
566 }
567 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_textPool.Alloc()) XMLText( this );
570 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p = start; // Back it up, all the text counts.
572 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 *node = returnNode;
575 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576}
577
578
Lee Thomason751da522012-02-10 08:50:51 -0800579bool XMLDocument::Accept( XMLVisitor* visitor ) const
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( visitor->VisitEnter( *this ) ) {
582 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
583 if ( !node->Accept( visitor ) ) {
584 break;
585 }
586 }
587 }
588 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800589}
Lee Thomason56bdd022012-02-09 18:16:58 -0800590
591
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592// --------- XMLNode ----------- //
593
594XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _document( doc ),
596 _parent( 0 ),
597 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200598 _prev( 0 ), _next( 0 ),
599 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800600{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601}
602
603
604XMLNode::~XMLNode()
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 if ( _parent ) {
608 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610}
611
Michael Daumling21626882013-10-22 17:03:37 +0200612const char* XMLNode::Value() const
613{
614 return _value.GetStr();
615}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800616
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800617void XMLNode::SetValue( const char* str, bool staticMem )
618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
622 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800625}
626
627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800629{
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300631 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700634
Dmitry-Mee3225b12014-09-03 11:03:11 +0400635 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800638}
639
640
641void XMLNode::Unlink( XMLNode* child )
642{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300643 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400667 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800668}
669
670
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
672{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300673 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300674 if ( addThis->_document != _document ) {
675 TIXMLASSERT( false );
676 return 0;
677 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800678 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700679
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 if ( _lastChild ) {
681 TIXMLASSERT( _firstChild );
682 TIXMLASSERT( _lastChild->_next == 0 );
683 _lastChild->_next = addThis;
684 addThis->_prev = _lastChild;
685 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
689 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( _firstChild == 0 );
691 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_prev = 0;
694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698}
699
700
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
702{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300703 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300704 if ( addThis->_document != _document ) {
705 TIXMLASSERT( false );
706 return 0;
707 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800708 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 if ( _firstChild ) {
711 TIXMLASSERT( _lastChild );
712 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 _firstChild->_prev = addThis;
715 addThis->_next = _firstChild;
716 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 }
720 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 TIXMLASSERT( _lastChild == 0 );
722 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 addThis->_prev = 0;
725 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400728 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729}
730
731
732XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
733{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300734 TIXMLASSERT( addThis );
735 if ( addThis->_document != _document ) {
736 TIXMLASSERT( false );
737 return 0;
738 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700739
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700741
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300743 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 return 0;
745 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 // The last node or the only node.
749 return InsertEndChild( addThis );
750 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800751 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 addThis->_prev = afterThis;
753 addThis->_next = afterThis->_next;
754 afterThis->_next->_prev = addThis;
755 afterThis->_next = addThis;
756 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800758}
759
760
761
762
Lee Thomason56bdd022012-02-09 18:16:58 -0800763const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 XMLElement* element = node->ToElement();
767 if ( element ) {
768 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
769 return element;
770 }
771 }
772 }
773 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800774}
775
776
Lee Thomason56bdd022012-02-09 18:16:58 -0800777const XMLElement* XMLNode::LastChildElement( const char* value ) const
778{
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 XMLElement* element = node->ToElement();
781 if ( element ) {
782 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
783 return element;
784 }
785 }
786 }
787 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800788}
789
790
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800791const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
792{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400793 for( XMLNode* node=this->_next; node; node = node->_next ) {
794 const XMLElement* element = node->ToElement();
795 if ( element
796 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
797 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
799 }
800 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800801}
802
803
804const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
805{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400806 for( XMLNode* node=_prev; node; node = node->_prev ) {
807 const XMLElement* element = node->ToElement();
808 if ( element
809 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
810 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
812 }
813 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800814}
815
816
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800817char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800818{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 // This is a recursive method, but thinking about it "at the current level"
820 // it is a pretty simple flat list:
821 // <foo/>
822 // <!-- comment -->
823 //
824 // With a special case:
825 // <foo>
826 // </foo>
827 // <!-- comment -->
828 //
829 // Where the closing element (/foo) *must* be the next thing after the opening
830 // element, and the names must match. BUT the tricky bit is that the closing
831 // element will be read by the child.
832 //
833 // 'endTag' is the end tag for this node, it is returned by a call to a child.
834 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 while( p && *p ) {
837 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 if ( p == 0 || node == 0 ) {
841 break;
842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 StrPair endTag;
845 p = node->ParseDeep( p, &endTag );
846 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400847 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 if ( !_document->Error() ) {
849 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 }
851 break;
852 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400854 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500856 // We read the end tag. Return it to the parent.
857 if ( ele->ClosingType() == XMLElement::CLOSING ) {
858 if ( parentEnd ) {
859 ele->_value.TransferTo( parentEnd );
860 }
861 node->_memPool->SetTracked(); // created and then immediately deleted.
862 DeleteNode( node );
863 return p;
864 }
865
866 // Handle an end tag returned to this level.
867 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400868 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400870 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 }
872 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400873 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 }
875 else if ( !endTag.Empty() ) {
876 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400877 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 }
879 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 if ( mismatch ) {
881 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500882 DeleteNode( node );
883 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400884 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
JayXondbfdd8f2014-12-12 20:07:14 -0500886 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800889}
890
Dmitry-Mee3225b12014-09-03 11:03:11 +0400891void XMLNode::DeleteNode( XMLNode* node )
892{
893 if ( node == 0 ) {
894 return;
895 }
896 MemPool* pool = node->_memPool;
897 node->~XMLNode();
898 pool->Free( node );
899}
900
Lee Thomason3cebdc42015-01-05 17:16:28 -0800901void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300902{
903 TIXMLASSERT( insertThis );
904 TIXMLASSERT( insertThis->_document == _document );
905
906 if ( insertThis->_parent )
907 insertThis->_parent->Unlink( insertThis );
908 else
909 insertThis->_memPool->SetTracked();
910}
911
Lee Thomason5492a1c2012-01-23 15:32:10 -0800912// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 const char* start = p;
916 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 return p;
922 }
923 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
925 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 flags |= StrPair::COLLAPSE_WHITESPACE;
927 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700928
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 if ( p && *p ) {
931 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300932 }
933 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300934 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 }
936 }
937 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800938}
939
940
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800941XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
942{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
947 text->SetCData( this->CData() );
948 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800949}
950
951
952bool XMLText::ShallowEqual( const XMLNode* compare ) const
953{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400954 const XMLText* text = compare->ToText();
955 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956}
957
958
Lee Thomason56bdd022012-02-09 18:16:58 -0800959bool XMLText::Accept( XMLVisitor* visitor ) const
960{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300961 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800963}
964
965
Lee Thomason3f57d272012-01-11 15:30:03 -0800966// --------- XMLComment ---------- //
967
Lee Thomasone4422302012-01-20 17:59:50 -0800968XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800969{
970}
971
972
Lee Thomasonce0763e2012-01-11 15:43:54 -0800973XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800974{
Lee Thomason3f57d272012-01-11 15:30:03 -0800975}
976
977
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800978char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 // Comment parses as text.
981 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700984 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 }
986 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800987}
988
989
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800990XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
996 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800997}
998
999
1000bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1001{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001002 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 const XMLComment* comment = compare->ToComment();
1004 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
Lee Thomason751da522012-02-10 08:50:51 -08001008bool XMLComment::Accept( XMLVisitor* visitor ) const
1009{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001010 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001012}
Lee Thomason56bdd022012-02-09 18:16:58 -08001013
1014
Lee Thomason50f97b22012-02-11 16:33:40 -08001015// --------- XMLDeclaration ---------- //
1016
1017XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1018{
1019}
1020
1021
1022XMLDeclaration::~XMLDeclaration()
1023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001025}
1026
1027
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001028char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001029{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 // Declaration parses as text.
1031 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001032 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001034 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 }
1036 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001037}
1038
1039
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001040XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1041{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 }
1045 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1046 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001047}
1048
1049
1050bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1051{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001052 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001053 const XMLDeclaration* declaration = compare->ToDeclaration();
1054 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055}
1056
1057
1058
Lee Thomason50f97b22012-02-11 16:33:40 -08001059bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1060{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001061 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
1065// --------- XMLUnknown ---------- //
1066
1067XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1068{
1069}
1070
1071
1072XMLUnknown::~XMLUnknown()
1073{
1074}
1075
1076
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001077char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Unknown parses as text.
1080 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001081
Lee Thomason624d43f2012-10-12 10:58:48 -07001082 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 }
1086 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001087}
1088
1089
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001090XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 }
1095 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1096 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001097}
1098
1099
1100bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1101{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001102 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001103 const XMLUnknown* unknown = compare->ToUnknown();
1104 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001105}
1106
1107
Lee Thomason50f97b22012-02-11 16:33:40 -08001108bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1109{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001110 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001112}
1113
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001114// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001115
1116const char* XMLAttribute::Name() const
1117{
1118 return _name.GetStr();
1119}
1120
1121const char* XMLAttribute::Value() const
1122{
1123 return _value.GetStr();
1124}
1125
Lee Thomason6f381b72012-03-02 12:59:39 -08001126char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( !p || !*p ) {
1131 return 0;
1132 }
Lee Thomason22aead12012-01-23 13:29:35 -08001133
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 // Skip white space before =
1135 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001136 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 return 0;
1138 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001139
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 ++p; // move up to opening quote
1141 p = XMLUtil::SkipWhiteSpace( p );
1142 if ( *p != '\"' && *p != '\'' ) {
1143 return 0;
1144 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001145
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 char endTag[2] = { *p, 0 };
1147 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001148
Lee Thomason624d43f2012-10-12 10:58:48 -07001149 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001151}
1152
1153
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001154void XMLAttribute::SetName( const char* n )
1155{
Lee Thomason624d43f2012-10-12 10:58:48 -07001156 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001157}
1158
1159
Lee Thomason2fa81722012-11-09 12:37:46 -08001160XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( XMLUtil::ToInt( Value(), value )) {
1163 return XML_NO_ERROR;
1164 }
1165 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
1167
1168
Lee Thomason2fa81722012-11-09 12:37:46 -08001169XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( XMLUtil::ToUnsigned( Value(), value )) {
1172 return XML_NO_ERROR;
1173 }
1174 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175}
1176
1177
Lee Thomason2fa81722012-11-09 12:37:46 -08001178XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 if ( XMLUtil::ToBool( Value(), value )) {
1181 return XML_NO_ERROR;
1182 }
1183 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184}
1185
1186
Lee Thomason2fa81722012-11-09 12:37:46 -08001187XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( XMLUtil::ToFloat( Value(), value )) {
1190 return XML_NO_ERROR;
1191 }
1192 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001193}
1194
1195
Lee Thomason2fa81722012-11-09 12:37:46 -08001196XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( XMLUtil::ToDouble( Value(), value )) {
1199 return XML_NO_ERROR;
1200 }
1201 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001202}
1203
1204
1205void XMLAttribute::SetAttribute( const char* v )
1206{
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208}
1209
1210
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211void XMLAttribute::SetAttribute( int v )
1212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 char buf[BUF_SIZE];
1214 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001215 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001216}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001217
1218
1219void XMLAttribute::SetAttribute( unsigned v )
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 char buf[BUF_SIZE];
1222 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001224}
1225
1226
1227void XMLAttribute::SetAttribute( bool v )
1228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 char buf[BUF_SIZE];
1230 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001232}
1233
1234void XMLAttribute::SetAttribute( double v )
1235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 char buf[BUF_SIZE];
1237 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239}
1240
1241void XMLAttribute::SetAttribute( float v )
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 char buf[BUF_SIZE];
1244 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001245 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246}
1247
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001248
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001249// --------- XMLElement ---------- //
1250XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 _closingType( 0 ),
1252 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001253{
1254}
1255
1256
1257XMLElement::~XMLElement()
1258{
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 while( _rootAttribute ) {
1260 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001261 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001264}
1265
1266
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001267const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1268{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001269 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1271 return a;
1272 }
1273 }
1274 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001275}
1276
1277
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001278const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 const XMLAttribute* a = FindAttribute( name );
1281 if ( !a ) {
1282 return 0;
1283 }
1284 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1285 return a->Value();
1286 }
1287 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001288}
1289
1290
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001291const char* XMLElement::GetText() const
1292{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001294 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 }
1296 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001297}
1298
1299
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001300void XMLElement::SetText( const char* inText )
1301{
Uli Kusterer869bb592014-01-21 01:36:16 +01001302 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001303 FirstChild()->SetValue( inText );
1304 else {
1305 XMLText* theText = GetDocument()->NewText( inText );
1306 InsertFirstChild( theText );
1307 }
1308}
1309
Lee Thomason5bb2d802014-01-24 10:42:57 -08001310
1311void XMLElement::SetText( int v )
1312{
1313 char buf[BUF_SIZE];
1314 XMLUtil::ToStr( v, buf, BUF_SIZE );
1315 SetText( buf );
1316}
1317
1318
1319void XMLElement::SetText( unsigned v )
1320{
1321 char buf[BUF_SIZE];
1322 XMLUtil::ToStr( v, buf, BUF_SIZE );
1323 SetText( buf );
1324}
1325
1326
1327void XMLElement::SetText( bool v )
1328{
1329 char buf[BUF_SIZE];
1330 XMLUtil::ToStr( v, buf, BUF_SIZE );
1331 SetText( buf );
1332}
1333
1334
1335void XMLElement::SetText( float v )
1336{
1337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( v, buf, BUF_SIZE );
1339 SetText( buf );
1340}
1341
1342
1343void XMLElement::SetText( double v )
1344{
1345 char buf[BUF_SIZE];
1346 XMLUtil::ToStr( v, buf, BUF_SIZE );
1347 SetText( buf );
1348}
1349
1350
MortenMacFly4ee49f12013-01-14 20:03:14 +01001351XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001354 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 return XML_SUCCESS;
1357 }
1358 return XML_CAN_NOT_CONVERT_TEXT;
1359 }
1360 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001361}
1362
1363
MortenMacFly4ee49f12013-01-14 20:03:14 +01001364XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001365{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001367 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 return XML_SUCCESS;
1370 }
1371 return XML_CAN_NOT_CONVERT_TEXT;
1372 }
1373 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001374}
1375
1376
MortenMacFly4ee49f12013-01-14 20:03:14 +01001377XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001380 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001381 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 return XML_SUCCESS;
1383 }
1384 return XML_CAN_NOT_CONVERT_TEXT;
1385 }
1386 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001387}
1388
1389
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001393 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001394 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 return XML_SUCCESS;
1396 }
1397 return XML_CAN_NOT_CONVERT_TEXT;
1398 }
1399 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001400}
1401
1402
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001406 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 return XML_SUCCESS;
1409 }
1410 return XML_CAN_NOT_CONVERT_TEXT;
1411 }
1412 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001413}
1414
1415
1416
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001417XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 XMLAttribute* last = 0;
1420 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1425 break;
1426 }
1427 }
1428 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001429 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1431 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 }
1435 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001439 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001442}
1443
1444
U-Stream\Leeae25a442012-02-17 17:48:16 -08001445void XMLElement::DeleteAttribute( const char* name )
1446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1450 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001456 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 break;
1458 }
1459 prev = a;
1460 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001461}
1462
1463
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001464char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 const char* start = p;
1467 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001468
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 // Read the attributes.
1470 while( p ) {
1471 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001472 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 return 0;
1475 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001476
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001478 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001479 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1481 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001482 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001483
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001486 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 return 0;
1489 }
1490 // There is a minor bug here: if the attribute in the source xml
1491 // document is duplicated, it will not be detected and the
1492 // attribute will be doubly added. However, tracking the 'prevAttribute'
1493 // avoids re-scanning the attribute list. Preferring performance for
1494 // now, may reconsider in the future.
1495 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 }
1501 prevAttribute = attrib;
1502 }
1503 // end of the tag
1504 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 return p+2; // done; sealed element.
1507 }
1508 // end of the tag
1509 else if ( *p == '>' ) {
1510 ++p;
1511 break;
1512 }
1513 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 return 0;
1516 }
1517 }
1518 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001519}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001520
Dmitry-Mee3225b12014-09-03 11:03:11 +04001521void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1522{
1523 if ( attribute == 0 ) {
1524 return;
1525 }
1526 MemPool* pool = attribute->_memPool;
1527 attribute->~XMLAttribute();
1528 pool->Free( attribute );
1529}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001530
Lee Thomason67d61312012-01-24 16:01:51 -08001531//
1532// <ele></ele>
1533// <ele>foo<b>bar</b></ele>
1534//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001535char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 // Read the element name.
1538 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001539
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 // The closing element is the </element> form. It is
1541 // parsed just like a regular element then deleted from
1542 // the DOM.
1543 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 ++p;
1546 }
Lee Thomason67d61312012-01-24 16:01:51 -08001547
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 p = _value.ParseName( p );
1549 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 return 0;
1551 }
Lee Thomason67d61312012-01-24 16:01:51 -08001552
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 return p;
1556 }
Lee Thomason67d61312012-01-24 16:01:51 -08001557
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 p = XMLNode::ParseDeep( p, strPair );
1559 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001560}
1561
1562
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563
1564XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 }
1569 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1570 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1571 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1572 }
1573 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001574}
1575
1576
1577bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1578{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001579 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 const XMLElement* other = compare->ToElement();
1581 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 const XMLAttribute* a=FirstAttribute();
1584 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001585
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 while ( a && b ) {
1587 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1588 return false;
1589 }
1590 a = a->Next();
1591 b = b->Next();
1592 }
1593 if ( a || b ) {
1594 // different count
1595 return false;
1596 }
1597 return true;
1598 }
1599 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001600}
1601
1602
Lee Thomason751da522012-02-10 08:50:51 -08001603bool XMLElement::Accept( XMLVisitor* visitor ) const
1604{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001605 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1608 if ( !node->Accept( visitor ) ) {
1609 break;
1610 }
1611 }
1612 }
1613 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001614}
Lee Thomason56bdd022012-02-09 18:16:58 -08001615
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616
Lee Thomason3f57d272012-01-11 15:30:03 -08001617// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001618
1619// Warning: List must match 'enum XMLError'
1620const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1621 "XML_SUCCESS",
1622 "XML_NO_ATTRIBUTE",
1623 "XML_WRONG_ATTRIBUTE_TYPE",
1624 "XML_ERROR_FILE_NOT_FOUND",
1625 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1626 "XML_ERROR_FILE_READ_ERROR",
1627 "XML_ERROR_ELEMENT_MISMATCH",
1628 "XML_ERROR_PARSING_ELEMENT",
1629 "XML_ERROR_PARSING_ATTRIBUTE",
1630 "XML_ERROR_IDENTIFYING_TAG",
1631 "XML_ERROR_PARSING_TEXT",
1632 "XML_ERROR_PARSING_CDATA",
1633 "XML_ERROR_PARSING_COMMENT",
1634 "XML_ERROR_PARSING_DECLARATION",
1635 "XML_ERROR_PARSING_UNKNOWN",
1636 "XML_ERROR_EMPTY_DOCUMENT",
1637 "XML_ERROR_MISMATCHED_ELEMENT",
1638 "XML_ERROR_PARSING",
1639 "XML_CAN_NOT_CONVERT_TEXT",
1640 "XML_NO_TEXT_NODE"
1641};
1642
1643
Lee Thomason624d43f2012-10-12 10:58:48 -07001644XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 _writeBOM( false ),
1647 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001648 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _whitespace( whitespace ),
1650 _errorStr1( 0 ),
1651 _errorStr2( 0 ),
1652 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001653{
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001656
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658XMLDocument::~XMLDocument()
1659{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001660 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001661}
1662
1663
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001664void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001665{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666 DeleteChildren();
1667
Dmitry-Meab37df82014-11-28 12:08:36 +03001668#ifdef DEBUG
1669 const bool hadError = Error();
1670#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _errorID = XML_NO_ERROR;
1672 _errorStr1 = 0;
1673 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001674
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 delete [] _charBuffer;
1676 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001677
1678#if 0
1679 _textPool.Trace( "text" );
1680 _elementPool.Trace( "element" );
1681 _commentPool.Trace( "comment" );
1682 _attributePool.Trace( "attribute" );
1683#endif
1684
1685#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001686 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001687 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1688 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1689 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1690 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1691 }
1692#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001693}
1694
Lee Thomason3f57d272012-01-11 15:30:03 -08001695
Lee Thomason2c85a712012-01-31 08:24:24 -08001696XMLElement* XMLDocument::NewElement( const char* name )
1697{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001698 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001699 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1700 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 ele->SetName( name );
1702 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001703}
1704
1705
Lee Thomason1ff38e02012-02-14 18:18:16 -08001706XMLComment* XMLDocument::NewComment( const char* str )
1707{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001708 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1710 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 comment->SetValue( str );
1712 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001713}
1714
1715
1716XMLText* XMLDocument::NewText( const char* str )
1717{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001718 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1720 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 text->SetValue( str );
1722 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001723}
1724
1725
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001726XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1727{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001728 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1730 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1732 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001733}
1734
1735
1736XMLUnknown* XMLDocument::NewUnknown( const char* str )
1737{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001738 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1740 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 unk->SetValue( str );
1742 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001743}
1744
Dmitry-Me01578db2014-08-19 10:18:48 +04001745static FILE* callfopen( const char* filepath, const char* mode )
1746{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001747 TIXMLASSERT( filepath );
1748 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001749#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1750 FILE* fp = 0;
1751 errno_t err = fopen_s( &fp, filepath, mode );
1752 if ( err ) {
1753 return 0;
1754 }
1755#else
1756 FILE* fp = fopen( filepath, mode );
1757#endif
1758 return fp;
1759}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001760
1761void XMLDocument::DeleteNode( XMLNode* node ) {
1762 TIXMLASSERT( node );
1763 TIXMLASSERT(node->_document == this );
1764 if (node->_parent) {
1765 node->_parent->DeleteChild( node );
1766 }
1767 else {
1768 // Isn't in the tree.
1769 // Use the parent delete.
1770 // Also, we need to mark it tracked: we 'know'
1771 // it was never used.
1772 node->_memPool->SetTracked();
1773 // Call the static XMLNode version:
1774 XMLNode::DeleteNode(node);
1775 }
1776}
1777
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001778
Lee Thomason2fa81722012-11-09 12:37:46 -08001779XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001780{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001781 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001782 FILE* fp = callfopen( filename, "rb" );
1783 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 }
1787 LoadFile( fp );
1788 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001790}
1791
1792
Lee Thomason2fa81722012-11-09 12:37:46 -08001793XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001794{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001795 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001797 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001798 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001799 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1800 return _errorID;
1801 }
1802
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001804 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001806 if ( filelength == -1L ) {
1807 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1808 return _errorID;
1809 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001811 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001813 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001816
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 _charBuffer = new char[size+1];
1818 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 if ( read != size ) {
1820 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001823
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825
Dmitry-Me97476b72015-01-01 16:15:57 +03001826 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001828}
1829
1830
Lee Thomason2fa81722012-11-09 12:37:46 -08001831XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832{
Dmitry-Me01578db2014-08-19 10:18:48 +04001833 FILE* fp = callfopen( filename, "w" );
1834 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 }
1838 SaveFile(fp, compact);
1839 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001841}
1842
1843
Lee Thomason2fa81722012-11-09 12:37:46 -08001844XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001845{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 XMLPrinter stream( fp, compact );
1847 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001849}
1850
Lee Thomason1ff38e02012-02-14 18:18:16 -08001851
Lee Thomason2fa81722012-11-09 12:37:46 -08001852XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001853{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001854 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001855
Lee Thomason82d32002014-02-21 22:47:18 -08001856 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
1860 if ( len == (size_t)(-1) ) {
1861 len = strlen( p );
1862 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 _charBuffer = new char[ len+1 ];
1864 memcpy( _charBuffer, p, len );
1865 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001866
Dmitry-Me97476b72015-01-01 16:15:57 +03001867 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001868 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001869 // clean up now essentially dangling memory.
1870 // and the parse fail can put objects in the
1871 // pools that are dead and inaccessible.
1872 DeleteChildren();
1873 _elementPool.Clear();
1874 _attributePool.Clear();
1875 _textPool.Clear();
1876 _commentPool.Clear();
1877 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001879}
1880
1881
PKEuS1c5f99e2013-07-06 11:28:39 +02001882void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001883{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 XMLPrinter stdStreamer( stdout );
1885 if ( !streamer ) {
1886 streamer = &stdStreamer;
1887 }
1888 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001889}
1890
1891
Lee Thomason2fa81722012-11-09 12:37:46 -08001892void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001893{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001894 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 _errorID = error;
1896 _errorStr1 = str1;
1897 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001898}
1899
Lee Thomason331596e2014-09-11 14:56:43 -07001900const char* XMLDocument::ErrorName() const
1901{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001902 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001903 return _errorNames[_errorID];
1904}
Lee Thomason5cae8972012-01-24 18:03:07 -08001905
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001906void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001907{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001908 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 static const int LEN = 20;
1910 char buf1[LEN] = { 0 };
1911 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001912
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 if ( _errorStr1 ) {
1914 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 if ( _errorStr2 ) {
1917 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001919
Lee Thomason331596e2014-09-11 14:56:43 -07001920 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1921 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001923}
1924
Dmitry-Me97476b72015-01-01 16:15:57 +03001925void XMLDocument::Parse()
1926{
1927 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1928 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001929 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001930 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001931 p = (char*) XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Me97476b72015-01-01 16:15:57 +03001932 if ( !*p ) {
1933 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1934 return;
1935 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001936 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001937}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001938
PKEuS1bfb9542013-08-04 13:51:17 +02001939XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 _elementJustOpened( false ),
1941 _firstElement( true ),
1942 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001943 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 _textDepth( -1 ),
1945 _processEntities( true ),
1946 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _entityFlag[i] = false;
1950 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 }
1952 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001953 const char entityValue = entities[i].value;
1954 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1955 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001957 _restrictedEntityFlag[(unsigned char)'&'] = true;
1958 _restrictedEntityFlag[(unsigned char)'<'] = true;
1959 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001961}
1962
1963
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001964void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001965{
1966 va_list va;
1967 va_start( va, format );
1968
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 if ( _fp ) {
1970 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 }
1972 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001973#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001974 #if defined(WINCE)
1975 int len = 512;
1976 do {
1977 len = len*2;
1978 char* str = new char[len]();
1979 len = _vsnprintf(str, len, format, va);
1980 delete[] str;
1981 }while (len < 0);
1982 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001983 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001984 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985#else
1986 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001987#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 // Close out and re-start the va-args
1989 va_end( va );
1990 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001991 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1992#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001993 #if defined(WINCE)
1994 _vsnprintf( p, len+1, format, va );
1995 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001996 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001997 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001998#else
1999 vsnprintf( p, len+1, format, va );
2000#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002002 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002003}
2004
2005
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002006void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 for( int i=0; i<depth; ++i ) {
2009 Print( " " );
2010 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002011}
2012
2013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 // Look for runs of bytes between entities to print.
2017 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002019
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 while ( *q ) {
2022 // Remember, char is sometimes signed. (How many times has that bitten me?)
2023 if ( *q > 0 && *q < ENTITY_RANGE ) {
2024 // Check for entities. If one is found, flush
2025 // the stream up until the entity, write the
2026 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002027 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 while ( p < q ) {
2029 Print( "%c", *p );
2030 ++p;
2031 }
2032 for( int i=0; i<NUM_ENTITIES; ++i ) {
2033 if ( entities[i].value == *q ) {
2034 Print( "&%s;", entities[i].pattern );
2035 break;
2036 }
2037 }
2038 ++p;
2039 }
2040 }
2041 ++q;
2042 }
2043 }
2044 // Flush the remaining string. This will be the entire
2045 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 Print( "%s", p );
2048 }
Lee Thomason857b8682012-01-25 17:50:25 -08002049}
2050
U-Stream\Leeae25a442012-02-17 17:48:16 -08002051
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002052void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002055 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 -07002056 Print( "%s", bom );
2057 }
2058 if ( writeDec ) {
2059 PushDeclaration( "xml version=\"1.0\"" );
2060 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002061}
2062
2063
Uli Kusterer593a33d2014-02-01 12:48:51 +01002064void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002065{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002066 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002068
Uli Kusterer593a33d2014-02-01 12:48:51 +01002069 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002071 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002072 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002075
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _elementJustOpened = true;
2078 _firstElement = false;
2079 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002084{
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( " %s=\"", name );
2087 PrintString( value, false );
2088 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002089}
2090
2091
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002092void XMLPrinter::PushAttribute( const char* name, int v )
2093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 char buf[BUF_SIZE];
2095 XMLUtil::ToStr( v, buf, BUF_SIZE );
2096 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002097}
2098
2099
2100void XMLPrinter::PushAttribute( const char* name, unsigned v )
2101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 char buf[BUF_SIZE];
2103 XMLUtil::ToStr( v, buf, BUF_SIZE );
2104 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002105}
2106
2107
2108void XMLPrinter::PushAttribute( const char* name, bool v )
2109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 char buf[BUF_SIZE];
2111 XMLUtil::ToStr( v, buf, BUF_SIZE );
2112 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002113}
2114
2115
2116void XMLPrinter::PushAttribute( const char* name, double v )
2117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 char buf[BUF_SIZE];
2119 XMLUtil::ToStr( v, buf, BUF_SIZE );
2120 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002121}
2122
2123
Uli Kustererca412e82014-02-01 13:35:05 +01002124void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002125{
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 --_depth;
2127 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002128
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 Print( "/>" );
2131 }
2132 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002133 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
2137 Print( "</%s>", name );
2138 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002139
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _textDepth == _depth ) {
2141 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
Uli Kustererca412e82014-02-01 13:35:05 +01002143 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "\n" );
2145 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002147}
2148
2149
Dmitry-Mea092bc12014-12-23 17:57:05 +03002150void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002151{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002152 if ( !_elementJustOpened ) {
2153 return;
2154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002157}
2158
2159
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002160void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002161{
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002163
Dmitry-Mea092bc12014-12-23 17:57:05 +03002164 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 if ( cdata ) {
2166 Print( "<![CDATA[" );
2167 Print( "%s", text );
2168 Print( "]]>" );
2169 }
2170 else {
2171 PrintString( text, true );
2172 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002173}
2174
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002175void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 char buf[BUF_SIZE];
2178 XMLUtil::ToStr( value, buf, BUF_SIZE );
2179 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002180}
2181
2182
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002183void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 char buf[BUF_SIZE];
2186 XMLUtil::ToStr( value, buf, BUF_SIZE );
2187 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002188}
2189
2190
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002191void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 char buf[BUF_SIZE];
2194 XMLUtil::ToStr( value, buf, BUF_SIZE );
2195 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002196}
2197
2198
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002199void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 char buf[BUF_SIZE];
2202 XMLUtil::ToStr( value, buf, BUF_SIZE );
2203 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002204}
2205
2206
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002207void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 char buf[BUF_SIZE];
2210 XMLUtil::ToStr( value, buf, BUF_SIZE );
2211 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002212}
2213
Lee Thomason5cae8972012-01-24 18:03:07 -08002214
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002215void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002216{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002217 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002224}
Lee Thomason751da522012-02-10 08:50:51 -08002225
2226
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002227void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002228{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002229 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236}
2237
2238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002240{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002241 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248}
2249
2250
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002251bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002252{
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 if ( doc.HasBOM() ) {
2255 PushHeader( true, false );
2256 }
2257 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002258}
2259
2260
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002261bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002262{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002263 const XMLElement* parentElem = element.Parent()->ToElement();
2264 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2265 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 while ( attribute ) {
2267 PushAttribute( attribute->Name(), attribute->Value() );
2268 attribute = attribute->Next();
2269 }
2270 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002271}
2272
2273
Uli Kustererca412e82014-02-01 13:35:05 +01002274bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002275{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002276 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002278}
2279
2280
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002281bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 PushText( text.Value(), text.CData() );
2284 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 PushComment( comment.Value() );
2291 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002292}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 PushDeclaration( declaration.Value() );
2297 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298}
2299
2300
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002301bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 PushUnknown( unknown.Value() );
2304 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002306
Lee Thomason685b8952012-11-12 13:00:06 -08002307} // namespace tinyxml2
2308