blob: 113f884d0c2a816851862449330fc2439011d2a8 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
354 ptrdiff_t delta = 0;
355 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 if ( *(p+2) == 'x' ) {
358 // Hexadecimal.
359 if ( !*(p+3) ) {
360 return 0;
361 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 const char* q = p+3;
364 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 if ( !q || !*q ) {
367 return 0;
368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 delta = q-p;
371 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 while ( *q != 'x' ) {
374 if ( *q >= '0' && *q <= '9' ) {
375 ucs += mult * (*q - '0');
376 }
377 else if ( *q >= 'a' && *q <= 'f' ) {
378 ucs += mult * (*q - 'a' + 10);
379 }
380 else if ( *q >= 'A' && *q <= 'F' ) {
381 ucs += mult * (*q - 'A' + 10 );
382 }
383 else {
384 return 0;
385 }
386 mult *= 16;
387 --q;
388 }
389 }
390 else {
391 // Decimal.
392 if ( !*(p+2) ) {
393 return 0;
394 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 const char* q = p+2;
397 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 if ( !q || !*q ) {
400 return 0;
401 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 delta = q-p;
404 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 while ( *q != '#' ) {
407 if ( *q >= '0' && *q <= '9' ) {
408 ucs += mult * (*q - '0');
409 }
410 else {
411 return 0;
412 }
413 mult *= 10;
414 --q;
415 }
416 }
417 // convert the UCS to UTF-8
418 ConvertUTF32ToUTF8( ucs, value, length );
419 return p + delta + 1;
420 }
421 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800422}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800423
424
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700425void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442/*
443 ToStr() of a number is a very tricky topic.
444 https://github.com/leethomason/tinyxml2/issues/106
445*/
Lee Thomason21be8822012-07-15 17:27:22 -0700446void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458bool XMLUtil::ToInt( const char* str, int* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
461 return true;
462 }
463 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700464}
465
466bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474bool XMLUtil::ToBool( const char* str, bool* value )
475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700476 int ival = 0;
477 if ( ToInt( str, &ival )) {
478 *value = (ival==0) ? false : true;
479 return true;
480 }
481 if ( StringEqual( str, "true" ) ) {
482 *value = true;
483 return true;
484 }
485 else if ( StringEqual( str, "false" ) ) {
486 *value = false;
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
493bool XMLUtil::ToFloat( const char* str, float* value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToDouble( const char* str, double* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
504 return true;
505 }
506 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700507}
508
509
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700510char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400512 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300514 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return p;
516 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800519 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const char* xmlHeader = { "<?" };
521 static const char* commentHeader = { "<!--" };
522 static const char* dtdHeader = { "<!" };
523 static const char* cdataHeader = { "<![CDATA[" };
524 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 static const int xmlHeaderLen = 2;
527 static const int commentHeaderLen = 4;
528 static const int dtdHeaderLen = 2;
529 static const int cdataHeaderLen = 9;
530 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800531
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
533 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400534 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300536 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300542 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLComment( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += commentHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300548 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += cdataHeaderLen;
553 text->SetCData( true );
554 }
555 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300556 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300562 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700563 returnNode = new (_elementPool.Alloc()) XMLElement( this );
564 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 p += elementHeaderLen;
566 }
567 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_textPool.Alloc()) XMLText( this );
570 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p = start; // Back it up, all the text counts.
572 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 *node = returnNode;
575 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576}
577
578
Lee Thomason751da522012-02-10 08:50:51 -0800579bool XMLDocument::Accept( XMLVisitor* visitor ) const
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( visitor->VisitEnter( *this ) ) {
582 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
583 if ( !node->Accept( visitor ) ) {
584 break;
585 }
586 }
587 }
588 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800589}
Lee Thomason56bdd022012-02-09 18:16:58 -0800590
591
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592// --------- XMLNode ----------- //
593
594XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _document( doc ),
596 _parent( 0 ),
597 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200598 _prev( 0 ), _next( 0 ),
599 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800600{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601}
602
603
604XMLNode::~XMLNode()
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 if ( _parent ) {
608 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610}
611
Michael Daumling21626882013-10-22 17:03:37 +0200612const char* XMLNode::Value() const
613{
614 return _value.GetStr();
615}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800616
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800617void XMLNode::SetValue( const char* str, bool staticMem )
618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
622 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800625}
626
627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800629{
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300631 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700634
Dmitry-Mee3225b12014-09-03 11:03:11 +0400635 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800638}
639
640
641void XMLNode::Unlink( XMLNode* child )
642{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300643 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400667 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800668}
669
670
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
672{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300673 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300674 if ( addThis->_document != _document ) {
675 TIXMLASSERT( false );
676 return 0;
677 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700678
Michael Daumlinged523282013-10-23 07:47:29 +0200679 if (addThis->_parent)
680 addThis->_parent->Unlink( addThis );
681 else
682 addThis->_memPool->SetTracked();
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 Thomason3b7927e2013-10-26 21:50:46 -0700712
Michael Daumlinged523282013-10-23 07:47:29 +0200713 if (addThis->_parent)
714 addThis->_parent->Unlink( addThis );
715 else
716 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 if ( _firstChild ) {
719 TIXMLASSERT( _lastChild );
720 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800721
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 _firstChild->_prev = addThis;
723 addThis->_next = _firstChild;
724 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
728 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 TIXMLASSERT( _lastChild == 0 );
730 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_prev = 0;
733 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400736 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737}
738
739
740XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
741{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300742 TIXMLASSERT( addThis );
743 if ( addThis->_document != _document ) {
744 TIXMLASSERT( false );
745 return 0;
746 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700747
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700749
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300751 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 return 0;
753 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800754
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 // The last node or the only node.
757 return InsertEndChild( addThis );
758 }
Michael Daumlinged523282013-10-23 07:47:29 +0200759 if (addThis->_parent)
760 addThis->_parent->Unlink( addThis );
761 else
762 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 addThis->_prev = afterThis;
764 addThis->_next = afterThis->_next;
765 afterThis->_next->_prev = addThis;
766 afterThis->_next = addThis;
767 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800769}
770
771
772
773
Lee Thomason56bdd022012-02-09 18:16:58 -0800774const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800775{
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 XMLElement* element = node->ToElement();
778 if ( element ) {
779 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
780 return element;
781 }
782 }
783 }
784 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800785}
786
787
Lee Thomason56bdd022012-02-09 18:16:58 -0800788const XMLElement* XMLNode::LastChildElement( const char* value ) const
789{
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 XMLElement* element = node->ToElement();
792 if ( element ) {
793 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
794 return element;
795 }
796 }
797 }
798 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800799}
800
801
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800802const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
803{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400804 for( XMLNode* node=this->_next; node; node = node->_next ) {
805 const XMLElement* element = node->ToElement();
806 if ( element
807 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
808 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
810 }
811 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800812}
813
814
815const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
816{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400817 for( XMLNode* node=_prev; node; node = node->_prev ) {
818 const XMLElement* element = node->ToElement();
819 if ( element
820 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
821 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 }
824 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800825}
826
827
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800828char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 // This is a recursive method, but thinking about it "at the current level"
831 // it is a pretty simple flat list:
832 // <foo/>
833 // <!-- comment -->
834 //
835 // With a special case:
836 // <foo>
837 // </foo>
838 // <!-- comment -->
839 //
840 // Where the closing element (/foo) *must* be the next thing after the opening
841 // element, and the names must match. BUT the tricky bit is that the closing
842 // element will be read by the child.
843 //
844 // 'endTag' is the end tag for this node, it is returned by a call to a child.
845 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 while( p && *p ) {
848 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 if ( p == 0 || node == 0 ) {
852 break;
853 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800854
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 StrPair endTag;
856 p = node->ParseDeep( p, &endTag );
857 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400858 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 if ( !_document->Error() ) {
860 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 }
862 break;
863 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800864
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400865 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400867 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800869 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800871 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400872 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 return p;
874 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800875
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 // Handle an end tag returned to this level.
877 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400879 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400884 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
886 else if ( !endTag.Empty() ) {
887 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400891 if ( mismatch ) {
892 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500893 DeleteNode( node );
894 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400895 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
JayXondbfdd8f2014-12-12 20:07:14 -0500897 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 }
899 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800900}
901
Dmitry-Mee3225b12014-09-03 11:03:11 +0400902void XMLNode::DeleteNode( XMLNode* node )
903{
904 if ( node == 0 ) {
905 return;
906 }
907 MemPool* pool = node->_memPool;
908 node->~XMLNode();
909 pool->Free( node );
910}
911
Lee Thomason5492a1c2012-01-23 15:32:10 -0800912// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 const char* start = p;
916 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 return p;
922 }
923 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
925 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 flags |= StrPair::COLLAPSE_WHITESPACE;
927 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700928
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700931 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 }
933 if ( p && *p ) {
934 return p-1;
935 }
936 }
937 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800938}
939
940
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800941XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
942{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
947 text->SetCData( this->CData() );
948 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800949}
950
951
952bool XMLText::ShallowEqual( const XMLNode* compare ) const
953{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400954 const XMLText* text = compare->ToText();
955 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956}
957
958
Lee Thomason56bdd022012-02-09 18:16:58 -0800959bool XMLText::Accept( XMLVisitor* visitor ) const
960{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300961 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800963}
964
965
Lee Thomason3f57d272012-01-11 15:30:03 -0800966// --------- XMLComment ---------- //
967
Lee Thomasone4422302012-01-20 17:59:50 -0800968XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800969{
970}
971
972
Lee Thomasonce0763e2012-01-11 15:43:54 -0800973XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800974{
Lee Thomason3f57d272012-01-11 15:30:03 -0800975}
976
977
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800978char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 // Comment parses as text.
981 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700984 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 }
986 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800987}
988
989
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800990XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
996 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800997}
998
999
1000bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1001{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001002 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 const XMLComment* comment = compare->ToComment();
1004 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
Lee Thomason751da522012-02-10 08:50:51 -08001008bool XMLComment::Accept( XMLVisitor* visitor ) const
1009{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001010 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001012}
Lee Thomason56bdd022012-02-09 18:16:58 -08001013
1014
Lee Thomason50f97b22012-02-11 16:33:40 -08001015// --------- XMLDeclaration ---------- //
1016
1017XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1018{
1019}
1020
1021
1022XMLDeclaration::~XMLDeclaration()
1023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001025}
1026
1027
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001028char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001029{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 // Declaration parses as text.
1031 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001032 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001034 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 }
1036 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001037}
1038
1039
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001040XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1041{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 }
1045 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1046 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001047}
1048
1049
1050bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1051{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001052 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001053 const XMLDeclaration* declaration = compare->ToDeclaration();
1054 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055}
1056
1057
1058
Lee Thomason50f97b22012-02-11 16:33:40 -08001059bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1060{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001061 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
1065// --------- XMLUnknown ---------- //
1066
1067XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1068{
1069}
1070
1071
1072XMLUnknown::~XMLUnknown()
1073{
1074}
1075
1076
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001077char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Unknown parses as text.
1080 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001081
Lee Thomason624d43f2012-10-12 10:58:48 -07001082 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 }
1086 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001087}
1088
1089
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001090XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 }
1095 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1096 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001097}
1098
1099
1100bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1101{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001102 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001103 const XMLUnknown* unknown = compare->ToUnknown();
1104 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001105}
1106
1107
Lee Thomason50f97b22012-02-11 16:33:40 -08001108bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1109{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001110 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001112}
1113
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001114// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001115
1116const char* XMLAttribute::Name() const
1117{
1118 return _name.GetStr();
1119}
1120
1121const char* XMLAttribute::Value() const
1122{
1123 return _value.GetStr();
1124}
1125
Lee Thomason6f381b72012-03-02 12:59:39 -08001126char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( !p || !*p ) {
1131 return 0;
1132 }
Lee Thomason22aead12012-01-23 13:29:35 -08001133
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 // Skip white space before =
1135 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001136 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 return 0;
1138 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001139
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 ++p; // move up to opening quote
1141 p = XMLUtil::SkipWhiteSpace( p );
1142 if ( *p != '\"' && *p != '\'' ) {
1143 return 0;
1144 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001145
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 char endTag[2] = { *p, 0 };
1147 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001148
Lee Thomason624d43f2012-10-12 10:58:48 -07001149 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001151}
1152
1153
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001154void XMLAttribute::SetName( const char* n )
1155{
Lee Thomason624d43f2012-10-12 10:58:48 -07001156 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001157}
1158
1159
Lee Thomason2fa81722012-11-09 12:37:46 -08001160XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( XMLUtil::ToInt( Value(), value )) {
1163 return XML_NO_ERROR;
1164 }
1165 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
1167
1168
Lee Thomason2fa81722012-11-09 12:37:46 -08001169XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( XMLUtil::ToUnsigned( Value(), value )) {
1172 return XML_NO_ERROR;
1173 }
1174 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175}
1176
1177
Lee Thomason2fa81722012-11-09 12:37:46 -08001178XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 if ( XMLUtil::ToBool( Value(), value )) {
1181 return XML_NO_ERROR;
1182 }
1183 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184}
1185
1186
Lee Thomason2fa81722012-11-09 12:37:46 -08001187XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( XMLUtil::ToFloat( Value(), value )) {
1190 return XML_NO_ERROR;
1191 }
1192 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001193}
1194
1195
Lee Thomason2fa81722012-11-09 12:37:46 -08001196XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( XMLUtil::ToDouble( Value(), value )) {
1199 return XML_NO_ERROR;
1200 }
1201 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001202}
1203
1204
1205void XMLAttribute::SetAttribute( const char* v )
1206{
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208}
1209
1210
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211void XMLAttribute::SetAttribute( int v )
1212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 char buf[BUF_SIZE];
1214 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001215 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001216}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001217
1218
1219void XMLAttribute::SetAttribute( unsigned v )
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 char buf[BUF_SIZE];
1222 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001224}
1225
1226
1227void XMLAttribute::SetAttribute( bool v )
1228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 char buf[BUF_SIZE];
1230 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001232}
1233
1234void XMLAttribute::SetAttribute( double v )
1235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 char buf[BUF_SIZE];
1237 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239}
1240
1241void XMLAttribute::SetAttribute( float v )
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 char buf[BUF_SIZE];
1244 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001245 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246}
1247
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001248
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001249// --------- XMLElement ---------- //
1250XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 _closingType( 0 ),
1252 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001253{
1254}
1255
1256
1257XMLElement::~XMLElement()
1258{
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 while( _rootAttribute ) {
1260 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001261 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001264}
1265
1266
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001267const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1268{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001269 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1271 return a;
1272 }
1273 }
1274 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001275}
1276
1277
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001278const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 const XMLAttribute* a = FindAttribute( name );
1281 if ( !a ) {
1282 return 0;
1283 }
1284 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1285 return a->Value();
1286 }
1287 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001288}
1289
1290
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001291const char* XMLElement::GetText() const
1292{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001294 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 }
1296 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001297}
1298
1299
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001300void XMLElement::SetText( const char* inText )
1301{
Uli Kusterer869bb592014-01-21 01:36:16 +01001302 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001303 FirstChild()->SetValue( inText );
1304 else {
1305 XMLText* theText = GetDocument()->NewText( inText );
1306 InsertFirstChild( theText );
1307 }
1308}
1309
Lee Thomason5bb2d802014-01-24 10:42:57 -08001310
1311void XMLElement::SetText( int v )
1312{
1313 char buf[BUF_SIZE];
1314 XMLUtil::ToStr( v, buf, BUF_SIZE );
1315 SetText( buf );
1316}
1317
1318
1319void XMLElement::SetText( unsigned v )
1320{
1321 char buf[BUF_SIZE];
1322 XMLUtil::ToStr( v, buf, BUF_SIZE );
1323 SetText( buf );
1324}
1325
1326
1327void XMLElement::SetText( bool v )
1328{
1329 char buf[BUF_SIZE];
1330 XMLUtil::ToStr( v, buf, BUF_SIZE );
1331 SetText( buf );
1332}
1333
1334
1335void XMLElement::SetText( float v )
1336{
1337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( v, buf, BUF_SIZE );
1339 SetText( buf );
1340}
1341
1342
1343void XMLElement::SetText( double v )
1344{
1345 char buf[BUF_SIZE];
1346 XMLUtil::ToStr( v, buf, BUF_SIZE );
1347 SetText( buf );
1348}
1349
1350
MortenMacFly4ee49f12013-01-14 20:03:14 +01001351XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001354 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 return XML_SUCCESS;
1357 }
1358 return XML_CAN_NOT_CONVERT_TEXT;
1359 }
1360 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001361}
1362
1363
MortenMacFly4ee49f12013-01-14 20:03:14 +01001364XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001365{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001367 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 return XML_SUCCESS;
1370 }
1371 return XML_CAN_NOT_CONVERT_TEXT;
1372 }
1373 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001374}
1375
1376
MortenMacFly4ee49f12013-01-14 20:03:14 +01001377XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001380 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001381 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 return XML_SUCCESS;
1383 }
1384 return XML_CAN_NOT_CONVERT_TEXT;
1385 }
1386 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001387}
1388
1389
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001393 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001394 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 return XML_SUCCESS;
1396 }
1397 return XML_CAN_NOT_CONVERT_TEXT;
1398 }
1399 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001400}
1401
1402
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001406 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 return XML_SUCCESS;
1409 }
1410 return XML_CAN_NOT_CONVERT_TEXT;
1411 }
1412 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001413}
1414
1415
1416
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001417XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 XMLAttribute* last = 0;
1420 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1425 break;
1426 }
1427 }
1428 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001429 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1431 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 }
1435 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001439 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001442}
1443
1444
U-Stream\Leeae25a442012-02-17 17:48:16 -08001445void XMLElement::DeleteAttribute( const char* name )
1446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1450 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001456 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 break;
1458 }
1459 prev = a;
1460 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001461}
1462
1463
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001464char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 const char* start = p;
1467 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001468
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 // Read the attributes.
1470 while( p ) {
1471 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001472 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 return 0;
1475 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001476
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001478 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001479 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1481 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001482 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001483
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001486 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 return 0;
1489 }
1490 // There is a minor bug here: if the attribute in the source xml
1491 // document is duplicated, it will not be detected and the
1492 // attribute will be doubly added. However, tracking the 'prevAttribute'
1493 // avoids re-scanning the attribute list. Preferring performance for
1494 // now, may reconsider in the future.
1495 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 }
1501 prevAttribute = attrib;
1502 }
1503 // end of the tag
1504 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 return p+2; // done; sealed element.
1507 }
1508 // end of the tag
1509 else if ( *p == '>' ) {
1510 ++p;
1511 break;
1512 }
1513 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 return 0;
1516 }
1517 }
1518 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001519}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001520
Dmitry-Mee3225b12014-09-03 11:03:11 +04001521void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1522{
1523 if ( attribute == 0 ) {
1524 return;
1525 }
1526 MemPool* pool = attribute->_memPool;
1527 attribute->~XMLAttribute();
1528 pool->Free( attribute );
1529}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001530
Lee Thomason67d61312012-01-24 16:01:51 -08001531//
1532// <ele></ele>
1533// <ele>foo<b>bar</b></ele>
1534//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001535char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 // Read the element name.
1538 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001539
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 // The closing element is the </element> form. It is
1541 // parsed just like a regular element then deleted from
1542 // the DOM.
1543 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 ++p;
1546 }
Lee Thomason67d61312012-01-24 16:01:51 -08001547
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 p = _value.ParseName( p );
1549 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 return 0;
1551 }
Lee Thomason67d61312012-01-24 16:01:51 -08001552
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 return p;
1556 }
Lee Thomason67d61312012-01-24 16:01:51 -08001557
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 p = XMLNode::ParseDeep( p, strPair );
1559 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001560}
1561
1562
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563
1564XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 }
1569 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1570 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1571 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1572 }
1573 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001574}
1575
1576
1577bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1578{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001579 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 const XMLElement* other = compare->ToElement();
1581 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 const XMLAttribute* a=FirstAttribute();
1584 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001585
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 while ( a && b ) {
1587 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1588 return false;
1589 }
1590 a = a->Next();
1591 b = b->Next();
1592 }
1593 if ( a || b ) {
1594 // different count
1595 return false;
1596 }
1597 return true;
1598 }
1599 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001600}
1601
1602
Lee Thomason751da522012-02-10 08:50:51 -08001603bool XMLElement::Accept( XMLVisitor* visitor ) const
1604{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001605 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1608 if ( !node->Accept( visitor ) ) {
1609 break;
1610 }
1611 }
1612 }
1613 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001614}
Lee Thomason56bdd022012-02-09 18:16:58 -08001615
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616
Lee Thomason3f57d272012-01-11 15:30:03 -08001617// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001618
1619// Warning: List must match 'enum XMLError'
1620const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1621 "XML_SUCCESS",
1622 "XML_NO_ATTRIBUTE",
1623 "XML_WRONG_ATTRIBUTE_TYPE",
1624 "XML_ERROR_FILE_NOT_FOUND",
1625 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1626 "XML_ERROR_FILE_READ_ERROR",
1627 "XML_ERROR_ELEMENT_MISMATCH",
1628 "XML_ERROR_PARSING_ELEMENT",
1629 "XML_ERROR_PARSING_ATTRIBUTE",
1630 "XML_ERROR_IDENTIFYING_TAG",
1631 "XML_ERROR_PARSING_TEXT",
1632 "XML_ERROR_PARSING_CDATA",
1633 "XML_ERROR_PARSING_COMMENT",
1634 "XML_ERROR_PARSING_DECLARATION",
1635 "XML_ERROR_PARSING_UNKNOWN",
1636 "XML_ERROR_EMPTY_DOCUMENT",
1637 "XML_ERROR_MISMATCHED_ELEMENT",
1638 "XML_ERROR_PARSING",
1639 "XML_CAN_NOT_CONVERT_TEXT",
1640 "XML_NO_TEXT_NODE"
1641};
1642
1643
Lee Thomason624d43f2012-10-12 10:58:48 -07001644XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 _writeBOM( false ),
1647 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001648 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _whitespace( whitespace ),
1650 _errorStr1( 0 ),
1651 _errorStr2( 0 ),
1652 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001653{
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001656
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658XMLDocument::~XMLDocument()
1659{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001660 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001661}
1662
1663
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001664void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001665{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666 DeleteChildren();
1667
Dmitry-Meab37df82014-11-28 12:08:36 +03001668#ifdef DEBUG
1669 const bool hadError = Error();
1670#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _errorID = XML_NO_ERROR;
1672 _errorStr1 = 0;
1673 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001674
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 delete [] _charBuffer;
1676 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001677
1678#if 0
1679 _textPool.Trace( "text" );
1680 _elementPool.Trace( "element" );
1681 _commentPool.Trace( "comment" );
1682 _attributePool.Trace( "attribute" );
1683#endif
1684
1685#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001686 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001687 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1688 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1689 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1690 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1691 }
1692#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001693}
1694
Lee Thomason3f57d272012-01-11 15:30:03 -08001695
Lee Thomason2c85a712012-01-31 08:24:24 -08001696XMLElement* XMLDocument::NewElement( const char* name )
1697{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001698 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001699 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1700 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 ele->SetName( name );
1702 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001703}
1704
1705
Lee Thomason1ff38e02012-02-14 18:18:16 -08001706XMLComment* XMLDocument::NewComment( const char* str )
1707{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001708 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1710 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 comment->SetValue( str );
1712 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001713}
1714
1715
1716XMLText* XMLDocument::NewText( const char* str )
1717{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001718 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1720 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 text->SetValue( str );
1722 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001723}
1724
1725
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001726XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1727{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001728 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1730 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1732 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001733}
1734
1735
1736XMLUnknown* XMLDocument::NewUnknown( const char* str )
1737{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001738 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1740 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 unk->SetValue( str );
1742 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001743}
1744
Dmitry-Me01578db2014-08-19 10:18:48 +04001745static FILE* callfopen( const char* filepath, const char* mode )
1746{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001747 TIXMLASSERT( filepath );
1748 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001749#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1750 FILE* fp = 0;
1751 errno_t err = fopen_s( &fp, filepath, mode );
1752 if ( err ) {
1753 return 0;
1754 }
1755#else
1756 FILE* fp = fopen( filepath, mode );
1757#endif
1758 return fp;
1759}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001760
1761void XMLDocument::DeleteNode( XMLNode* node ) {
1762 TIXMLASSERT( node );
1763 TIXMLASSERT(node->_document == this );
1764 if (node->_parent) {
1765 node->_parent->DeleteChild( node );
1766 }
1767 else {
1768 // Isn't in the tree.
1769 // Use the parent delete.
1770 // Also, we need to mark it tracked: we 'know'
1771 // it was never used.
1772 node->_memPool->SetTracked();
1773 // Call the static XMLNode version:
1774 XMLNode::DeleteNode(node);
1775 }
1776}
1777
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001778
Lee Thomason2fa81722012-11-09 12:37:46 -08001779XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001780{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001781 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001782 FILE* fp = callfopen( filename, "rb" );
1783 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 }
1787 LoadFile( fp );
1788 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001790}
1791
1792
Lee Thomason2fa81722012-11-09 12:37:46 -08001793XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001794{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001795 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001797 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001798 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001799 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1800 return _errorID;
1801 }
1802
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001804 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001806 if ( filelength == -1L ) {
1807 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1808 return _errorID;
1809 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001811 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001813 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001816
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 _charBuffer = new char[size+1];
1818 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 if ( read != size ) {
1820 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001823
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001829 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001833
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1835 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001836}
1837
1838
Lee Thomason2fa81722012-11-09 12:37:46 -08001839XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001840{
Dmitry-Me01578db2014-08-19 10:18:48 +04001841 FILE* fp = callfopen( filename, "w" );
1842 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 }
1846 SaveFile(fp, compact);
1847 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001849}
1850
1851
Lee Thomason2fa81722012-11-09 12:37:46 -08001852XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001853{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 XMLPrinter stream( fp, compact );
1855 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001857}
1858
Lee Thomason1ff38e02012-02-14 18:18:16 -08001859
Lee Thomason2fa81722012-11-09 12:37:46 -08001860XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001861{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001862 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001863
Lee Thomason82d32002014-02-21 22:47:18 -08001864 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 }
1868 if ( len == (size_t)(-1) ) {
1869 len = strlen( p );
1870 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 _charBuffer = new char[ len+1 ];
1872 memcpy( _charBuffer, p, len );
1873 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001874
Dmitry-Me5b4a5162014-12-23 17:36:28 +03001875 const char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001877 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001878 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001882
Thomas Roß1470edc2013-05-10 15:44:12 +02001883 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001884 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001885 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001886 // clean up now essentially dangling memory.
1887 // and the parse fail can put objects in the
1888 // pools that are dead and inaccessible.
1889 DeleteChildren();
1890 _elementPool.Clear();
1891 _attributePool.Clear();
1892 _textPool.Clear();
1893 _commentPool.Clear();
1894 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001896}
1897
1898
PKEuS1c5f99e2013-07-06 11:28:39 +02001899void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 XMLPrinter stdStreamer( stdout );
1902 if ( !streamer ) {
1903 streamer = &stdStreamer;
1904 }
1905 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001906}
1907
1908
Lee Thomason2fa81722012-11-09 12:37:46 -08001909void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001910{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001911 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 _errorID = error;
1913 _errorStr1 = str1;
1914 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001915}
1916
Lee Thomason331596e2014-09-11 14:56:43 -07001917const char* XMLDocument::ErrorName() const
1918{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001919 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001920 return _errorNames[_errorID];
1921}
Lee Thomason5cae8972012-01-24 18:03:07 -08001922
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001923void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001924{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001925 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 static const int LEN = 20;
1927 char buf1[LEN] = { 0 };
1928 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001929
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 if ( _errorStr1 ) {
1931 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 if ( _errorStr2 ) {
1934 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001936
Lee Thomason331596e2014-09-11 14:56:43 -07001937 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1938 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001940}
1941
1942
PKEuS1bfb9542013-08-04 13:51:17 +02001943XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 _elementJustOpened( false ),
1945 _firstElement( true ),
1946 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001947 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 _textDepth( -1 ),
1949 _processEntities( true ),
1950 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 _entityFlag[i] = false;
1954 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001955 }
1956 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001957 const char entityValue = entities[i].value;
1958 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1959 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001961 _restrictedEntityFlag[(unsigned char)'&'] = true;
1962 _restrictedEntityFlag[(unsigned char)'<'] = true;
1963 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001965}
1966
1967
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001968void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001969{
1970 va_list va;
1971 va_start( va, format );
1972
Lee Thomason624d43f2012-10-12 10:58:48 -07001973 if ( _fp ) {
1974 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 }
1976 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001977#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001978 #if defined(WINCE)
1979 int len = 512;
1980 do {
1981 len = len*2;
1982 char* str = new char[len]();
1983 len = _vsnprintf(str, len, format, va);
1984 delete[] str;
1985 }while (len < 0);
1986 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001987 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001988 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989#else
1990 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001991#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 // Close out and re-start the va-args
1993 va_end( va );
1994 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001995 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1996#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001997 #if defined(WINCE)
1998 _vsnprintf( p, len+1, format, va );
1999 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002000 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002001 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002002#else
2003 vsnprintf( p, len+1, format, va );
2004#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002006 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002007}
2008
2009
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002010void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 for( int i=0; i<depth; ++i ) {
2013 Print( " " );
2014 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002015}
2016
2017
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002018void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 // Look for runs of bytes between entities to print.
2021 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002023
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 while ( *q ) {
2026 // Remember, char is sometimes signed. (How many times has that bitten me?)
2027 if ( *q > 0 && *q < ENTITY_RANGE ) {
2028 // Check for entities. If one is found, flush
2029 // the stream up until the entity, write the
2030 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002031 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 while ( p < q ) {
2033 Print( "%c", *p );
2034 ++p;
2035 }
2036 for( int i=0; i<NUM_ENTITIES; ++i ) {
2037 if ( entities[i].value == *q ) {
2038 Print( "&%s;", entities[i].pattern );
2039 break;
2040 }
2041 }
2042 ++p;
2043 }
2044 }
2045 ++q;
2046 }
2047 }
2048 // Flush the remaining string. This will be the entire
2049 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 Print( "%s", p );
2052 }
Lee Thomason857b8682012-01-25 17:50:25 -08002053}
2054
U-Stream\Leeae25a442012-02-17 17:48:16 -08002055
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002056void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002059 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 -07002060 Print( "%s", bom );
2061 }
2062 if ( writeDec ) {
2063 PushDeclaration( "xml version=\"1.0\"" );
2064 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002065}
2066
2067
Uli Kusterer593a33d2014-02-01 12:48:51 +01002068void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002069{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002070 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002071 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002072
Uli Kusterer593a33d2014-02-01 12:48:51 +01002073 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002075 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002076 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002079
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 _elementJustOpened = true;
2082 _firstElement = false;
2083 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002084}
2085
2086
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002087void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002088{
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 Print( " %s=\"", name );
2091 PrintString( value, false );
2092 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002093}
2094
2095
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002096void XMLPrinter::PushAttribute( const char* name, int v )
2097{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 char buf[BUF_SIZE];
2099 XMLUtil::ToStr( v, buf, BUF_SIZE );
2100 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002101}
2102
2103
2104void XMLPrinter::PushAttribute( const char* name, unsigned v )
2105{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 char buf[BUF_SIZE];
2107 XMLUtil::ToStr( v, buf, BUF_SIZE );
2108 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002109}
2110
2111
2112void XMLPrinter::PushAttribute( const char* name, bool v )
2113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 char buf[BUF_SIZE];
2115 XMLUtil::ToStr( v, buf, BUF_SIZE );
2116 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002117}
2118
2119
2120void XMLPrinter::PushAttribute( const char* name, double v )
2121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 char buf[BUF_SIZE];
2123 XMLUtil::ToStr( v, buf, BUF_SIZE );
2124 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002125}
2126
2127
Uli Kustererca412e82014-02-01 13:35:05 +01002128void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002129{
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 --_depth;
2131 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002132
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 Print( "/>" );
2135 }
2136 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002137 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 }
2141 Print( "</%s>", name );
2142 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002143
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 if ( _textDepth == _depth ) {
2145 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
Uli Kustererca412e82014-02-01 13:35:05 +01002147 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 Print( "\n" );
2149 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002151}
2152
2153
Dmitry-Mea092bc12014-12-23 17:57:05 +03002154void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002155{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002156 if ( !_elementJustOpened ) {
2157 return;
2158 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002161}
2162
2163
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002164void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002165{
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002167
Dmitry-Mea092bc12014-12-23 17:57:05 +03002168 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 if ( cdata ) {
2170 Print( "<![CDATA[" );
2171 Print( "%s", text );
2172 Print( "]]>" );
2173 }
2174 else {
2175 PrintString( text, true );
2176 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002177}
2178
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002179void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 char buf[BUF_SIZE];
2182 XMLUtil::ToStr( value, buf, BUF_SIZE );
2183 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002184}
2185
2186
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002187void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 char buf[BUF_SIZE];
2190 XMLUtil::ToStr( value, buf, BUF_SIZE );
2191 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002192}
2193
2194
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002195void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 char buf[BUF_SIZE];
2198 XMLUtil::ToStr( value, buf, BUF_SIZE );
2199 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002200}
2201
2202
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002203void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 char buf[BUF_SIZE];
2206 XMLUtil::ToStr( value, buf, BUF_SIZE );
2207 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002208}
2209
2210
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002211void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 char buf[BUF_SIZE];
2214 XMLUtil::ToStr( value, buf, BUF_SIZE );
2215 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002216}
2217
Lee Thomason5cae8972012-01-24 18:03:07 -08002218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002220{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002221 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002228}
Lee Thomason751da522012-02-10 08:50:51 -08002229
2230
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002231void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002232{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002233 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002240}
2241
2242
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002243void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002245 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002252}
2253
2254
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002255bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002256{
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 if ( doc.HasBOM() ) {
2259 PushHeader( true, false );
2260 }
2261 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002262}
2263
2264
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002265bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002266{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002267 const XMLElement* parentElem = element.Parent()->ToElement();
2268 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2269 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 while ( attribute ) {
2271 PushAttribute( attribute->Name(), attribute->Value() );
2272 attribute = attribute->Next();
2273 }
2274 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002275}
2276
2277
Uli Kustererca412e82014-02-01 13:35:05 +01002278bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002279{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002280 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002282}
2283
2284
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002285bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 PushText( text.Value(), text.CData() );
2288 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002289}
2290
2291
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002292bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 PushComment( comment.Value() );
2295 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002296}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002298bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 PushDeclaration( declaration.Value() );
2301 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302}
2303
2304
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002305bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 PushUnknown( unknown.Value() );
2308 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002309}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002310
Lee Thomason685b8952012-11-12 13:00:06 -08002311} // namespace tinyxml2
2312