blob: 60f38ed1836a1bfa378bfe7e1ae0d450ff30c30a [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;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300354 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 ptrdiff_t delta = 0;
356 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 if ( *(p+2) == 'x' ) {
359 // Hexadecimal.
360 if ( !*(p+3) ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 const char* q = p+3;
365 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 if ( !q || !*q ) {
368 return 0;
369 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800370
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700371 delta = q-p;
372 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800373
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700374 while ( *q != 'x' ) {
375 if ( *q >= '0' && *q <= '9' ) {
376 ucs += mult * (*q - '0');
377 }
378 else if ( *q >= 'a' && *q <= 'f' ) {
379 ucs += mult * (*q - 'a' + 10);
380 }
381 else if ( *q >= 'A' && *q <= 'F' ) {
382 ucs += mult * (*q - 'A' + 10 );
383 }
384 else {
385 return 0;
386 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300387 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 mult *= 16;
389 --q;
390 }
391 }
392 else {
393 // Decimal.
394 if ( !*(p+2) ) {
395 return 0;
396 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800397
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 const char* q = p+2;
399 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700401 if ( !q || !*q ) {
402 return 0;
403 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800404
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 delta = q-p;
406 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 while ( *q != '#' ) {
409 if ( *q >= '0' && *q <= '9' ) {
410 ucs += mult * (*q - '0');
411 }
412 else {
413 return 0;
414 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300415 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 mult *= 10;
417 --q;
418 }
419 }
420 // convert the UCS to UTF-8
421 ConvertUTF32ToUTF8( ucs, value, length );
422 return p + delta + 1;
423 }
424 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800426
427
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700428void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
439
440void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800445/*
446 ToStr() of a number is a very tricky topic.
447 https://github.com/leethomason/tinyxml2/issues/106
448*/
Lee Thomason21be8822012-07-15 17:27:22 -0700449void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
450{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800451 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454
455void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
456{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800457 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460
461bool XMLUtil::ToInt( const char* str, int* value )
462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
464 return true;
465 }
466 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700467}
468
469bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
472 return true;
473 }
474 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700475}
476
477bool XMLUtil::ToBool( const char* str, bool* value )
478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 int ival = 0;
480 if ( ToInt( str, &ival )) {
481 *value = (ival==0) ? false : true;
482 return true;
483 }
484 if ( StringEqual( str, "true" ) ) {
485 *value = true;
486 return true;
487 }
488 else if ( StringEqual( str, "false" ) ) {
489 *value = false;
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495
496bool XMLUtil::ToFloat( const char* str, float* value )
497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700498 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
499 return true;
500 }
501 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700502}
503
504bool XMLUtil::ToDouble( const char* str, double* value )
505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
507 return true;
508 }
509 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700510}
511
512
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700513char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400515 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300517 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 return p;
519 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800520
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800522 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 static const char* xmlHeader = { "<?" };
524 static const char* commentHeader = { "<!--" };
525 static const char* dtdHeader = { "<!" };
526 static const char* cdataHeader = { "<![CDATA[" };
527 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 static const int xmlHeaderLen = 2;
530 static const int commentHeaderLen = 4;
531 static const int dtdHeaderLen = 2;
532 static const int cdataHeaderLen = 9;
533 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800534
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
536 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400537 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300539 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += xmlHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300545 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700546 returnNode = new (_commentPool.Alloc()) XMLComment( this );
547 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 p += commentHeaderLen;
549 }
550 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300551 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p += cdataHeaderLen;
556 text->SetCData( true );
557 }
558 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300559 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
561 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p += dtdHeaderLen;
563 }
564 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300565 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 returnNode = new (_elementPool.Alloc()) XMLElement( this );
567 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 p += elementHeaderLen;
569 }
570 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300571 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700572 returnNode = new (_textPool.Alloc()) XMLText( this );
573 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 p = start; // Back it up, all the text counts.
575 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 *node = returnNode;
578 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579}
580
581
Lee Thomason751da522012-02-10 08:50:51 -0800582bool XMLDocument::Accept( XMLVisitor* visitor ) const
583{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300584 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 if ( visitor->VisitEnter( *this ) ) {
586 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
587 if ( !node->Accept( visitor ) ) {
588 break;
589 }
590 }
591 }
592 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800593}
Lee Thomason56bdd022012-02-09 18:16:58 -0800594
595
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596// --------- XMLNode ----------- //
597
598XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700599 _document( doc ),
600 _parent( 0 ),
601 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200602 _prev( 0 ), _next( 0 ),
603 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605}
606
607
608XMLNode::~XMLNode()
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700611 if ( _parent ) {
612 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614}
615
Michael Daumling21626882013-10-22 17:03:37 +0200616const char* XMLNode::Value() const
617{
618 return _value.GetStr();
619}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800620
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800621void XMLNode::SetValue( const char* str, bool staticMem )
622{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
626 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800629}
630
631
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800632void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800633{
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300635 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700638
Dmitry-Mee3225b12014-09-03 11:03:11 +0400639 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800642}
643
644
645void XMLNode::Unlink( XMLNode* child )
646{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300647 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300648 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child == _firstChild ) {
650 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child == _lastChild ) {
653 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomasond923c672012-01-23 08:44:25 -0800655
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 if ( child->_prev ) {
657 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( child->_next ) {
660 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700662 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663}
664
665
U-Stream\Leeae25a442012-02-17 17:48:16 -0800666void XMLNode::DeleteChild( XMLNode* node )
667{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300668 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300669 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400671 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800672}
673
674
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
676{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300677 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300678 if ( addThis->_document != _document ) {
679 TIXMLASSERT( false );
680 return 0;
681 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800682 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700683
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 if ( _lastChild ) {
685 TIXMLASSERT( _firstChild );
686 TIXMLASSERT( _lastChild->_next == 0 );
687 _lastChild->_next = addThis;
688 addThis->_prev = _lastChild;
689 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800690
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 }
693 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 TIXMLASSERT( _firstChild == 0 );
695 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800696
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 addThis->_prev = 0;
698 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702}
703
704
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
706{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300707 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300708 if ( addThis->_document != _document ) {
709 TIXMLASSERT( false );
710 return 0;
711 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800712 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 if ( _firstChild ) {
715 TIXMLASSERT( _lastChild );
716 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 _firstChild->_prev = addThis;
719 addThis->_next = _firstChild;
720 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800721
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 }
724 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 TIXMLASSERT( _lastChild == 0 );
726 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800727
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 addThis->_prev = 0;
729 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400732 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800733}
734
735
736XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
737{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300738 TIXMLASSERT( addThis );
739 if ( addThis->_document != _document ) {
740 TIXMLASSERT( false );
741 return 0;
742 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700743
Dmitry-Meabb2d042014-12-09 12:59:31 +0300744 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700745
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300747 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 return 0;
749 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 // The last node or the only node.
753 return InsertEndChild( addThis );
754 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800755 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 addThis->_prev = afterThis;
757 addThis->_next = afterThis->_next;
758 afterThis->_next->_prev = addThis;
759 afterThis->_next = addThis;
760 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800762}
763
764
765
766
Lee Thomason56bdd022012-02-09 18:16:58 -0800767const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800768{
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 XMLElement* element = node->ToElement();
771 if ( element ) {
772 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
773 return element;
774 }
775 }
776 }
777 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800778}
779
780
Lee Thomason56bdd022012-02-09 18:16:58 -0800781const XMLElement* XMLNode::LastChildElement( const char* value ) const
782{
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 XMLElement* element = node->ToElement();
785 if ( element ) {
786 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
787 return element;
788 }
789 }
790 }
791 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800792}
793
794
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800795const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
796{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400797 for( XMLNode* node=this->_next; node; node = node->_next ) {
798 const XMLElement* element = node->ToElement();
799 if ( element
800 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
801 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
803 }
804 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800805}
806
807
808const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
809{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400810 for( XMLNode* node=_prev; node; node = node->_prev ) {
811 const XMLElement* element = node->ToElement();
812 if ( element
813 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
814 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 }
816 }
817 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800818}
819
820
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800821char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800822{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // This is a recursive method, but thinking about it "at the current level"
824 // it is a pretty simple flat list:
825 // <foo/>
826 // <!-- comment -->
827 //
828 // With a special case:
829 // <foo>
830 // </foo>
831 // <!-- comment -->
832 //
833 // Where the closing element (/foo) *must* be the next thing after the opening
834 // element, and the names must match. BUT the tricky bit is that the closing
835 // element will be read by the child.
836 //
837 // 'endTag' is the end tag for this node, it is returned by a call to a child.
838 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800839
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 while( p && *p ) {
841 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800842
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 if ( p == 0 || node == 0 ) {
845 break;
846 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800847
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 StrPair endTag;
849 p = node->ParseDeep( p, &endTag );
850 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400851 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 if ( !_document->Error() ) {
853 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 }
855 break;
856 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800857
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400858 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500860 // We read the end tag. Return it to the parent.
861 if ( ele->ClosingType() == XMLElement::CLOSING ) {
862 if ( parentEnd ) {
863 ele->_value.TransferTo( parentEnd );
864 }
865 node->_memPool->SetTracked(); // created and then immediately deleted.
866 DeleteNode( node );
867 return p;
868 }
869
870 // Handle an end tag returned to this level.
871 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400872 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300873 if ( endTag.Empty() ) {
874 if ( ele->ClosingType() == XMLElement::OPEN ) {
875 mismatch = true;
876 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300878 else {
879 if ( ele->ClosingType() != XMLElement::OPEN ) {
880 mismatch = true;
881 }
882 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400883 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400886 if ( mismatch ) {
887 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500888 DeleteNode( node );
889 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400890 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 }
JayXondbfdd8f2014-12-12 20:07:14 -0500892 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
894 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800895}
896
Dmitry-Mee3225b12014-09-03 11:03:11 +0400897void XMLNode::DeleteNode( XMLNode* node )
898{
899 if ( node == 0 ) {
900 return;
901 }
902 MemPool* pool = node->_memPool;
903 node->~XMLNode();
904 pool->Free( node );
905}
906
Lee Thomason3cebdc42015-01-05 17:16:28 -0800907void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300908{
909 TIXMLASSERT( insertThis );
910 TIXMLASSERT( insertThis->_document == _document );
911
912 if ( insertThis->_parent )
913 insertThis->_parent->Unlink( insertThis );
914 else
915 insertThis->_memPool->SetTracked();
916}
917
Lee Thomason5492a1c2012-01-23 15:32:10 -0800918// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800919char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800920{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 const char* start = p;
922 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700925 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 }
927 return p;
928 }
929 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
931 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 flags |= StrPair::COLLAPSE_WHITESPACE;
933 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700934
Lee Thomason624d43f2012-10-12 10:58:48 -0700935 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 if ( p && *p ) {
937 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300938 }
939 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300940 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 }
942 }
943 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800944}
945
946
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700950 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 }
952 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
953 text->SetCData( this->CData() );
954 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
958bool XMLText::ShallowEqual( const XMLNode* compare ) const
959{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400960 const XMLText* text = compare->ToText();
961 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800962}
963
964
Lee Thomason56bdd022012-02-09 18:16:58 -0800965bool XMLText::Accept( XMLVisitor* visitor ) const
966{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300967 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800969}
970
971
Lee Thomason3f57d272012-01-11 15:30:03 -0800972// --------- XMLComment ---------- //
973
Lee Thomasone4422302012-01-20 17:59:50 -0800974XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800975{
976}
977
978
Lee Thomasonce0763e2012-01-11 15:43:54 -0800979XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800980{
Lee Thomason3f57d272012-01-11 15:30:03 -0800981}
982
983
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800984char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 // Comment parses as text.
987 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800993}
994
995
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1002 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001003}
1004
1005
1006bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1007{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001008 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001009 const XMLComment* comment = compare->ToComment();
1010 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001011}
1012
1013
Lee Thomason751da522012-02-10 08:50:51 -08001014bool XMLComment::Accept( XMLVisitor* visitor ) const
1015{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001016 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001018}
Lee Thomason56bdd022012-02-09 18:16:58 -08001019
1020
Lee Thomason50f97b22012-02-11 16:33:40 -08001021// --------- XMLDeclaration ---------- //
1022
1023XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1024{
1025}
1026
1027
1028XMLDeclaration::~XMLDeclaration()
1029{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001031}
1032
1033
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001034char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 // Declaration parses as text.
1037 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001043}
1044
1045
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1052 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001053}
1054
1055
1056bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1057{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001058 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001059 const XMLDeclaration* declaration = compare->ToDeclaration();
1060 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001061}
1062
1063
1064
Lee Thomason50f97b22012-02-11 16:33:40 -08001065bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1066{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001067 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001069}
1070
1071// --------- XMLUnknown ---------- //
1072
1073XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1074{
1075}
1076
1077
1078XMLUnknown::~XMLUnknown()
1079{
1080}
1081
1082
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001083char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 // Unknown parses as text.
1086 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001087
Lee Thomason624d43f2012-10-12 10:58:48 -07001088 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001090 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 }
1092 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001093}
1094
1095
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1097{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001099 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 }
1101 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1102 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001103}
1104
1105
1106bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1107{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001108 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001109 const XMLUnknown* unknown = compare->ToUnknown();
1110 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001111}
1112
1113
Lee Thomason50f97b22012-02-11 16:33:40 -08001114bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1115{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001116 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001118}
1119
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001120// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001121
1122const char* XMLAttribute::Name() const
1123{
1124 return _name.GetStr();
1125}
1126
1127const char* XMLAttribute::Value() const
1128{
1129 return _value.GetStr();
1130}
1131
Lee Thomason6f381b72012-03-02 12:59:39 -08001132char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( !p || !*p ) {
1137 return 0;
1138 }
Lee Thomason22aead12012-01-23 13:29:35 -08001139
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 // Skip white space before =
1141 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001142 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 return 0;
1144 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001145
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 ++p; // move up to opening quote
1147 p = XMLUtil::SkipWhiteSpace( p );
1148 if ( *p != '\"' && *p != '\'' ) {
1149 return 0;
1150 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001151
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 char endTag[2] = { *p, 0 };
1153 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001154
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001157}
1158
1159
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001160void XMLAttribute::SetName( const char* n )
1161{
Lee Thomason624d43f2012-10-12 10:58:48 -07001162 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001163}
1164
1165
Lee Thomason2fa81722012-11-09 12:37:46 -08001166XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( XMLUtil::ToInt( Value(), value )) {
1169 return XML_NO_ERROR;
1170 }
1171 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToUnsigned( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
Lee Thomason2fa81722012-11-09 12:37:46 -08001184XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::ToBool( Value(), value )) {
1187 return XML_NO_ERROR;
1188 }
1189 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190}
1191
1192
Lee Thomason2fa81722012-11-09 12:37:46 -08001193XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( XMLUtil::ToFloat( Value(), value )) {
1196 return XML_NO_ERROR;
1197 }
1198 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001199}
1200
1201
Lee Thomason2fa81722012-11-09 12:37:46 -08001202XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( XMLUtil::ToDouble( Value(), value )) {
1205 return XML_NO_ERROR;
1206 }
1207 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208}
1209
1210
1211void XMLAttribute::SetAttribute( const char* v )
1212{
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214}
1215
1216
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217void XMLAttribute::SetAttribute( int v )
1218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 char buf[BUF_SIZE];
1220 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001221 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001222}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223
1224
1225void XMLAttribute::SetAttribute( unsigned v )
1226{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 char buf[BUF_SIZE];
1228 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001229 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001230}
1231
1232
1233void XMLAttribute::SetAttribute( bool v )
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 char buf[BUF_SIZE];
1236 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001237 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240void XMLAttribute::SetAttribute( double v )
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 char buf[BUF_SIZE];
1243 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001244 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001245}
1246
1247void XMLAttribute::SetAttribute( float v )
1248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 char buf[BUF_SIZE];
1250 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001252}
1253
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001254
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001255// --------- XMLElement ---------- //
1256XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001257 _closingType( 0 ),
1258 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001259{
1260}
1261
1262
1263XMLElement::~XMLElement()
1264{
Lee Thomason624d43f2012-10-12 10:58:48 -07001265 while( _rootAttribute ) {
1266 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001267 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001268 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001270}
1271
1272
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001273const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1274{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001275 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1277 return a;
1278 }
1279 }
1280 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001281}
1282
1283
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001284const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 const XMLAttribute* a = FindAttribute( name );
1287 if ( !a ) {
1288 return 0;
1289 }
1290 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1291 return a->Value();
1292 }
1293 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001294}
1295
1296
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001297const char* XMLElement::GetText() const
1298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001300 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 }
1302 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001303}
1304
1305
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001306void XMLElement::SetText( const char* inText )
1307{
Uli Kusterer869bb592014-01-21 01:36:16 +01001308 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001309 FirstChild()->SetValue( inText );
1310 else {
1311 XMLText* theText = GetDocument()->NewText( inText );
1312 InsertFirstChild( theText );
1313 }
1314}
1315
Lee Thomason5bb2d802014-01-24 10:42:57 -08001316
1317void XMLElement::SetText( int v )
1318{
1319 char buf[BUF_SIZE];
1320 XMLUtil::ToStr( v, buf, BUF_SIZE );
1321 SetText( buf );
1322}
1323
1324
1325void XMLElement::SetText( unsigned v )
1326{
1327 char buf[BUF_SIZE];
1328 XMLUtil::ToStr( v, buf, BUF_SIZE );
1329 SetText( buf );
1330}
1331
1332
1333void XMLElement::SetText( bool v )
1334{
1335 char buf[BUF_SIZE];
1336 XMLUtil::ToStr( v, buf, BUF_SIZE );
1337 SetText( buf );
1338}
1339
1340
1341void XMLElement::SetText( float v )
1342{
1343 char buf[BUF_SIZE];
1344 XMLUtil::ToStr( v, buf, BUF_SIZE );
1345 SetText( buf );
1346}
1347
1348
1349void XMLElement::SetText( double v )
1350{
1351 char buf[BUF_SIZE];
1352 XMLUtil::ToStr( v, buf, BUF_SIZE );
1353 SetText( buf );
1354}
1355
1356
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001360 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 return XML_SUCCESS;
1363 }
1364 return XML_CAN_NOT_CONVERT_TEXT;
1365 }
1366 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001367}
1368
1369
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001373 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 return XML_SUCCESS;
1376 }
1377 return XML_CAN_NOT_CONVERT_TEXT;
1378 }
1379 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001380}
1381
1382
MortenMacFly4ee49f12013-01-14 20:03:14 +01001383XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001386 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 return XML_SUCCESS;
1389 }
1390 return XML_CAN_NOT_CONVERT_TEXT;
1391 }
1392 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001393}
1394
1395
MortenMacFly4ee49f12013-01-14 20:03:14 +01001396XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001399 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 return XML_SUCCESS;
1402 }
1403 return XML_CAN_NOT_CONVERT_TEXT;
1404 }
1405 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001406}
1407
1408
MortenMacFly4ee49f12013-01-14 20:03:14 +01001409XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001412 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 return XML_SUCCESS;
1415 }
1416 return XML_CAN_NOT_CONVERT_TEXT;
1417 }
1418 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001419}
1420
1421
1422
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001423XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 XMLAttribute* last = 0;
1426 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1431 break;
1432 }
1433 }
1434 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001435 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1437 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 }
1444 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001445 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 }
1447 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001448}
1449
1450
U-Stream\Leeae25a442012-02-17 17:48:16 -08001451void XMLElement::DeleteAttribute( const char* name )
1452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1456 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001462 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 break;
1464 }
1465 prev = a;
1466 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001467}
1468
1469
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001470char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001471{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 const char* start = p;
1473 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001474
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 // Read the attributes.
1476 while( p ) {
1477 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001478 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 return 0;
1481 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001482
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001484 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001485 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1487 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001488 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001489
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001492 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 return 0;
1495 }
1496 // There is a minor bug here: if the attribute in the source xml
1497 // document is duplicated, it will not be detected and the
1498 // attribute will be doubly added. However, tracking the 'prevAttribute'
1499 // avoids re-scanning the attribute list. Preferring performance for
1500 // now, may reconsider in the future.
1501 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 }
1504 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 }
1507 prevAttribute = attrib;
1508 }
1509 // end of the tag
1510 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return p+2; // done; sealed element.
1513 }
1514 // end of the tag
1515 else if ( *p == '>' ) {
1516 ++p;
1517 break;
1518 }
1519 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return 0;
1522 }
1523 }
1524 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001525}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001526
Dmitry-Mee3225b12014-09-03 11:03:11 +04001527void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1528{
1529 if ( attribute == 0 ) {
1530 return;
1531 }
1532 MemPool* pool = attribute->_memPool;
1533 attribute->~XMLAttribute();
1534 pool->Free( attribute );
1535}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001536
Lee Thomason67d61312012-01-24 16:01:51 -08001537//
1538// <ele></ele>
1539// <ele>foo<b>bar</b></ele>
1540//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001541char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 // Read the element name.
1544 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001545
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 // The closing element is the </element> form. It is
1547 // parsed just like a regular element then deleted from
1548 // the DOM.
1549 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 ++p;
1552 }
Lee Thomason67d61312012-01-24 16:01:51 -08001553
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 p = _value.ParseName( p );
1555 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 return 0;
1557 }
Lee Thomason67d61312012-01-24 16:01:51 -08001558
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 return p;
1562 }
Lee Thomason67d61312012-01-24 16:01:51 -08001563
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 p = XMLNode::ParseDeep( p, strPair );
1565 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001566}
1567
1568
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569
1570XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001573 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1576 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1577 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1578 }
1579 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001580}
1581
1582
1583bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1584{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001585 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 const XMLElement* other = compare->ToElement();
1587 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001588
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 const XMLAttribute* a=FirstAttribute();
1590 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 while ( a && b ) {
1593 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1594 return false;
1595 }
1596 a = a->Next();
1597 b = b->Next();
1598 }
1599 if ( a || b ) {
1600 // different count
1601 return false;
1602 }
1603 return true;
1604 }
1605 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001606}
1607
1608
Lee Thomason751da522012-02-10 08:50:51 -08001609bool XMLElement::Accept( XMLVisitor* visitor ) const
1610{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001611 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1614 if ( !node->Accept( visitor ) ) {
1615 break;
1616 }
1617 }
1618 }
1619 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001620}
Lee Thomason56bdd022012-02-09 18:16:58 -08001621
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001622
Lee Thomason3f57d272012-01-11 15:30:03 -08001623// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001624
1625// Warning: List must match 'enum XMLError'
1626const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1627 "XML_SUCCESS",
1628 "XML_NO_ATTRIBUTE",
1629 "XML_WRONG_ATTRIBUTE_TYPE",
1630 "XML_ERROR_FILE_NOT_FOUND",
1631 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1632 "XML_ERROR_FILE_READ_ERROR",
1633 "XML_ERROR_ELEMENT_MISMATCH",
1634 "XML_ERROR_PARSING_ELEMENT",
1635 "XML_ERROR_PARSING_ATTRIBUTE",
1636 "XML_ERROR_IDENTIFYING_TAG",
1637 "XML_ERROR_PARSING_TEXT",
1638 "XML_ERROR_PARSING_CDATA",
1639 "XML_ERROR_PARSING_COMMENT",
1640 "XML_ERROR_PARSING_DECLARATION",
1641 "XML_ERROR_PARSING_UNKNOWN",
1642 "XML_ERROR_EMPTY_DOCUMENT",
1643 "XML_ERROR_MISMATCHED_ELEMENT",
1644 "XML_ERROR_PARSING",
1645 "XML_CAN_NOT_CONVERT_TEXT",
1646 "XML_NO_TEXT_NODE"
1647};
1648
1649
Lee Thomason624d43f2012-10-12 10:58:48 -07001650XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 _writeBOM( false ),
1653 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001654 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 _whitespace( whitespace ),
1656 _errorStr1( 0 ),
1657 _errorStr2( 0 ),
1658 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001659{
Lee Thomason624d43f2012-10-12 10:58:48 -07001660 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001661}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001662
1663
Lee Thomason3f57d272012-01-11 15:30:03 -08001664XMLDocument::~XMLDocument()
1665{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001666 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001667}
1668
1669
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001670void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001671{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001672 DeleteChildren();
1673
Dmitry-Meab37df82014-11-28 12:08:36 +03001674#ifdef DEBUG
1675 const bool hadError = Error();
1676#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 _errorID = XML_NO_ERROR;
1678 _errorStr1 = 0;
1679 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001680
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 delete [] _charBuffer;
1682 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001683
1684#if 0
1685 _textPool.Trace( "text" );
1686 _elementPool.Trace( "element" );
1687 _commentPool.Trace( "comment" );
1688 _attributePool.Trace( "attribute" );
1689#endif
1690
1691#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001692 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001693 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1694 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1695 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1696 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1697 }
1698#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001699}
1700
Lee Thomason3f57d272012-01-11 15:30:03 -08001701
Lee Thomason2c85a712012-01-31 08:24:24 -08001702XMLElement* XMLDocument::NewElement( const char* name )
1703{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001704 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1706 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 ele->SetName( name );
1708 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001709}
1710
1711
Lee Thomason1ff38e02012-02-14 18:18:16 -08001712XMLComment* XMLDocument::NewComment( const char* str )
1713{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001714 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1716 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 comment->SetValue( str );
1718 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001719}
1720
1721
1722XMLText* XMLDocument::NewText( const char* str )
1723{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001724 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1726 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 text->SetValue( str );
1728 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001729}
1730
1731
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001732XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1736 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1738 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001739}
1740
1741
1742XMLUnknown* XMLDocument::NewUnknown( const char* str )
1743{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001744 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1746 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 unk->SetValue( str );
1748 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749}
1750
Dmitry-Me01578db2014-08-19 10:18:48 +04001751static FILE* callfopen( const char* filepath, const char* mode )
1752{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001753 TIXMLASSERT( filepath );
1754 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001755#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1756 FILE* fp = 0;
1757 errno_t err = fopen_s( &fp, filepath, mode );
1758 if ( err ) {
1759 return 0;
1760 }
1761#else
1762 FILE* fp = fopen( filepath, mode );
1763#endif
1764 return fp;
1765}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001766
1767void XMLDocument::DeleteNode( XMLNode* node ) {
1768 TIXMLASSERT( node );
1769 TIXMLASSERT(node->_document == this );
1770 if (node->_parent) {
1771 node->_parent->DeleteChild( node );
1772 }
1773 else {
1774 // Isn't in the tree.
1775 // Use the parent delete.
1776 // Also, we need to mark it tracked: we 'know'
1777 // it was never used.
1778 node->_memPool->SetTracked();
1779 // Call the static XMLNode version:
1780 XMLNode::DeleteNode(node);
1781 }
1782}
1783
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001784
Lee Thomason2fa81722012-11-09 12:37:46 -08001785XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001786{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001787 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001788 FILE* fp = callfopen( filename, "rb" );
1789 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
1793 LoadFile( fp );
1794 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796}
1797
1798
Lee Thomason2fa81722012-11-09 12:37:46 -08001799XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001801 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001802
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001803 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001804 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001805 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1806 return _errorID;
1807 }
1808
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001810 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001812 if ( filelength == -1L ) {
1813 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1814 return _errorID;
1815 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001816
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001817 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001819 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001822
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 _charBuffer = new char[size+1];
1824 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 if ( read != size ) {
1826 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001829
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001831
Dmitry-Me97476b72015-01-01 16:15:57 +03001832 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834}
1835
1836
Lee Thomason2fa81722012-11-09 12:37:46 -08001837XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001838{
Dmitry-Me01578db2014-08-19 10:18:48 +04001839 FILE* fp = callfopen( filename, "w" );
1840 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 }
1844 SaveFile(fp, compact);
1845 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001847}
1848
1849
Lee Thomason2fa81722012-11-09 12:37:46 -08001850XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001851{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 XMLPrinter stream( fp, compact );
1853 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001855}
1856
Lee Thomason1ff38e02012-02-14 18:18:16 -08001857
Lee Thomason2fa81722012-11-09 12:37:46 -08001858XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001859{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001860 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001861
Lee Thomason82d32002014-02-21 22:47:18 -08001862 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 }
1866 if ( len == (size_t)(-1) ) {
1867 len = strlen( p );
1868 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 _charBuffer = new char[ len+1 ];
1870 memcpy( _charBuffer, p, len );
1871 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001872
Dmitry-Me97476b72015-01-01 16:15:57 +03001873 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001874 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001875 // clean up now essentially dangling memory.
1876 // and the parse fail can put objects in the
1877 // pools that are dead and inaccessible.
1878 DeleteChildren();
1879 _elementPool.Clear();
1880 _attributePool.Clear();
1881 _textPool.Clear();
1882 _commentPool.Clear();
1883 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001885}
1886
1887
PKEuS1c5f99e2013-07-06 11:28:39 +02001888void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 XMLPrinter stdStreamer( stdout );
1891 if ( !streamer ) {
1892 streamer = &stdStreamer;
1893 }
1894 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001895}
1896
1897
Lee Thomason2fa81722012-11-09 12:37:46 -08001898void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001899{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001900 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 _errorID = error;
1902 _errorStr1 = str1;
1903 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001904}
1905
Lee Thomason331596e2014-09-11 14:56:43 -07001906const char* XMLDocument::ErrorName() const
1907{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001908 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001909 return _errorNames[_errorID];
1910}
Lee Thomason5cae8972012-01-24 18:03:07 -08001911
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001912void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001913{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001914 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 static const int LEN = 20;
1916 char buf1[LEN] = { 0 };
1917 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001918
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 if ( _errorStr1 ) {
1920 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 if ( _errorStr2 ) {
1923 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001925
Lee Thomason331596e2014-09-11 14:56:43 -07001926 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1927 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001929}
1930
Dmitry-Me97476b72015-01-01 16:15:57 +03001931void XMLDocument::Parse()
1932{
1933 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1934 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001935 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001936 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001937 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001938 if ( !*p ) {
1939 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1940 return;
1941 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001942 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001943}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001944
PKEuS1bfb9542013-08-04 13:51:17 +02001945XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 _elementJustOpened( false ),
1947 _firstElement( true ),
1948 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001949 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _textDepth( -1 ),
1951 _processEntities( true ),
1952 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 _entityFlag[i] = false;
1956 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
1958 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001959 const char entityValue = entities[i].value;
1960 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1961 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001963 _restrictedEntityFlag[(unsigned char)'&'] = true;
1964 _restrictedEntityFlag[(unsigned char)'<'] = true;
1965 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001967}
1968
1969
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001970void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001971{
1972 va_list va;
1973 va_start( va, format );
1974
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 if ( _fp ) {
1976 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 }
1978 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001979#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001980 #if defined(WINCE)
1981 int len = 512;
1982 do {
1983 len = len*2;
1984 char* str = new char[len]();
1985 len = _vsnprintf(str, len, format, va);
1986 delete[] str;
1987 }while (len < 0);
1988 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001989 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001990 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001991#else
1992 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001993#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 // Close out and re-start the va-args
1995 va_end( va );
1996 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001997 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1998#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001999 #if defined(WINCE)
2000 _vsnprintf( p, len+1, format, va );
2001 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002002 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002003 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002004#else
2005 vsnprintf( p, len+1, format, va );
2006#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002008 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002009}
2010
2011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002012void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002013{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 for( int i=0; i<depth; ++i ) {
2015 Print( " " );
2016 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002017}
2018
2019
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002020void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 // Look for runs of bytes between entities to print.
2023 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002025
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 while ( *q ) {
2028 // Remember, char is sometimes signed. (How many times has that bitten me?)
2029 if ( *q > 0 && *q < ENTITY_RANGE ) {
2030 // Check for entities. If one is found, flush
2031 // the stream up until the entity, write the
2032 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002033 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 while ( p < q ) {
2035 Print( "%c", *p );
2036 ++p;
2037 }
2038 for( int i=0; i<NUM_ENTITIES; ++i ) {
2039 if ( entities[i].value == *q ) {
2040 Print( "&%s;", entities[i].pattern );
2041 break;
2042 }
2043 }
2044 ++p;
2045 }
2046 }
2047 ++q;
2048 }
2049 }
2050 // Flush the remaining string. This will be the entire
2051 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 Print( "%s", p );
2054 }
Lee Thomason857b8682012-01-25 17:50:25 -08002055}
2056
U-Stream\Leeae25a442012-02-17 17:48:16 -08002057
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002058void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002061 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 -07002062 Print( "%s", bom );
2063 }
2064 if ( writeDec ) {
2065 PushDeclaration( "xml version=\"1.0\"" );
2066 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002067}
2068
2069
Uli Kusterer593a33d2014-02-01 12:48:51 +01002070void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002071{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002072 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002074
Uli Kusterer593a33d2014-02-01 12:48:51 +01002075 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002077 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002078 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002081
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _elementJustOpened = true;
2084 _firstElement = false;
2085 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002086}
2087
2088
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002089void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002090{
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 Print( " %s=\"", name );
2093 PrintString( value, false );
2094 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002095}
2096
2097
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002098void XMLPrinter::PushAttribute( const char* name, int v )
2099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( v, buf, BUF_SIZE );
2102 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103}
2104
2105
2106void XMLPrinter::PushAttribute( const char* name, unsigned v )
2107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 char buf[BUF_SIZE];
2109 XMLUtil::ToStr( v, buf, BUF_SIZE );
2110 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002111}
2112
2113
2114void XMLPrinter::PushAttribute( const char* name, bool v )
2115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 char buf[BUF_SIZE];
2117 XMLUtil::ToStr( v, buf, BUF_SIZE );
2118 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002119}
2120
2121
2122void XMLPrinter::PushAttribute( const char* name, double v )
2123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 char buf[BUF_SIZE];
2125 XMLUtil::ToStr( v, buf, BUF_SIZE );
2126 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002127}
2128
2129
Uli Kustererca412e82014-02-01 13:35:05 +01002130void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002131{
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 --_depth;
2133 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002134
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 Print( "/>" );
2137 }
2138 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002139 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
2143 Print( "</%s>", name );
2144 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002145
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 if ( _textDepth == _depth ) {
2147 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
Uli Kustererca412e82014-02-01 13:35:05 +01002149 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( "\n" );
2151 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002153}
2154
2155
Dmitry-Mea092bc12014-12-23 17:57:05 +03002156void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002157{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002158 if ( !_elementJustOpened ) {
2159 return;
2160 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002163}
2164
2165
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002166void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002167{
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002169
Dmitry-Mea092bc12014-12-23 17:57:05 +03002170 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 if ( cdata ) {
2172 Print( "<![CDATA[" );
2173 Print( "%s", text );
2174 Print( "]]>" );
2175 }
2176 else {
2177 PrintString( text, true );
2178 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002179}
2180
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002181void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 char buf[BUF_SIZE];
2184 XMLUtil::ToStr( value, buf, BUF_SIZE );
2185 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002186}
2187
2188
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002189void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 char buf[BUF_SIZE];
2192 XMLUtil::ToStr( value, buf, BUF_SIZE );
2193 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002194}
2195
2196
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002197void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 char buf[BUF_SIZE];
2200 XMLUtil::ToStr( value, buf, BUF_SIZE );
2201 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002202}
2203
2204
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002205void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 char buf[BUF_SIZE];
2208 XMLUtil::ToStr( value, buf, BUF_SIZE );
2209 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002210}
2211
2212
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002213void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 char buf[BUF_SIZE];
2216 XMLUtil::ToStr( value, buf, BUF_SIZE );
2217 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002218}
2219
Lee Thomason5cae8972012-01-24 18:03:07 -08002220
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002221void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002222{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002223 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002230}
Lee Thomason751da522012-02-10 08:50:51 -08002231
2232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002233void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002235 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242}
2243
2244
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002245void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002247 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
2256
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002257bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002258{
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 if ( doc.HasBOM() ) {
2261 PushHeader( true, false );
2262 }
2263 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002264}
2265
2266
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002267bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002268{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002269 const XMLElement* parentElem = element.Parent()->ToElement();
2270 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2271 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 while ( attribute ) {
2273 PushAttribute( attribute->Name(), attribute->Value() );
2274 attribute = attribute->Next();
2275 }
2276 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002277}
2278
2279
Uli Kustererca412e82014-02-01 13:35:05 +01002280bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002281{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002282 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002284}
2285
2286
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002287bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 PushText( text.Value(), text.CData() );
2290 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002291}
2292
2293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 PushComment( comment.Value() );
2297 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002298}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002300bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 PushDeclaration( declaration.Value() );
2303 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304}
2305
2306
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002307bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 PushUnknown( unknown.Value() );
2310 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002311}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002312
Lee Thomason685b8952012-11-12 13:00:06 -08002313} // namespace tinyxml2
2314