blob: e5c040547504699933b102c149076f1dd1d19392 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
354 ptrdiff_t delta = 0;
355 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 if ( *(p+2) == 'x' ) {
358 // Hexadecimal.
359 if ( !*(p+3) ) {
360 return 0;
361 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 const char* q = p+3;
364 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 if ( !q || !*q ) {
367 return 0;
368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 delta = q-p;
371 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 while ( *q != 'x' ) {
374 if ( *q >= '0' && *q <= '9' ) {
375 ucs += mult * (*q - '0');
376 }
377 else if ( *q >= 'a' && *q <= 'f' ) {
378 ucs += mult * (*q - 'a' + 10);
379 }
380 else if ( *q >= 'A' && *q <= 'F' ) {
381 ucs += mult * (*q - 'A' + 10 );
382 }
383 else {
384 return 0;
385 }
386 mult *= 16;
387 --q;
388 }
389 }
390 else {
391 // Decimal.
392 if ( !*(p+2) ) {
393 return 0;
394 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 const char* q = p+2;
397 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 if ( !q || !*q ) {
400 return 0;
401 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 delta = q-p;
404 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 while ( *q != '#' ) {
407 if ( *q >= '0' && *q <= '9' ) {
408 ucs += mult * (*q - '0');
409 }
410 else {
411 return 0;
412 }
413 mult *= 10;
414 --q;
415 }
416 }
417 // convert the UCS to UTF-8
418 ConvertUTF32ToUTF8( ucs, value, length );
419 return p + delta + 1;
420 }
421 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800422}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800423
424
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700425void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442/*
443 ToStr() of a number is a very tricky topic.
444 https://github.com/leethomason/tinyxml2/issues/106
445*/
Lee Thomason21be8822012-07-15 17:27:22 -0700446void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458bool XMLUtil::ToInt( const char* str, int* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
461 return true;
462 }
463 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700464}
465
466bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474bool XMLUtil::ToBool( const char* str, bool* value )
475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700476 int ival = 0;
477 if ( ToInt( str, &ival )) {
478 *value = (ival==0) ? false : true;
479 return true;
480 }
481 if ( StringEqual( str, "true" ) ) {
482 *value = true;
483 return true;
484 }
485 else if ( StringEqual( str, "false" ) ) {
486 *value = false;
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
493bool XMLUtil::ToFloat( const char* str, float* value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToDouble( const char* str, double* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
504 return true;
505 }
506 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700507}
508
509
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700510char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400512 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300514 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return p;
516 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800519 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const char* xmlHeader = { "<?" };
521 static const char* commentHeader = { "<!--" };
522 static const char* dtdHeader = { "<!" };
523 static const char* cdataHeader = { "<![CDATA[" };
524 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 static const int xmlHeaderLen = 2;
527 static const int commentHeaderLen = 4;
528 static const int dtdHeaderLen = 2;
529 static const int cdataHeaderLen = 9;
530 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800531
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
533 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400534 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300536 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300542 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLComment( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += commentHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300548 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += cdataHeaderLen;
553 text->SetCData( true );
554 }
555 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300556 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300562 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700563 returnNode = new (_elementPool.Alloc()) XMLElement( this );
564 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 p += elementHeaderLen;
566 }
567 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_textPool.Alloc()) XMLText( this );
570 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p = start; // Back it up, all the text counts.
572 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 *node = returnNode;
575 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576}
577
578
Lee Thomason751da522012-02-10 08:50:51 -0800579bool XMLDocument::Accept( XMLVisitor* visitor ) const
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( visitor->VisitEnter( *this ) ) {
582 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
583 if ( !node->Accept( visitor ) ) {
584 break;
585 }
586 }
587 }
588 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800589}
Lee Thomason56bdd022012-02-09 18:16:58 -0800590
591
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592// --------- XMLNode ----------- //
593
594XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _document( doc ),
596 _parent( 0 ),
597 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200598 _prev( 0 ), _next( 0 ),
599 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800600{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601}
602
603
604XMLNode::~XMLNode()
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 if ( _parent ) {
608 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610}
611
Michael Daumling21626882013-10-22 17:03:37 +0200612const char* XMLNode::Value() const
613{
614 return _value.GetStr();
615}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800616
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800617void XMLNode::SetValue( const char* str, bool staticMem )
618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
622 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800625}
626
627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800629{
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300631 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700634
Dmitry-Mee3225b12014-09-03 11:03:11 +0400635 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800638}
639
640
641void XMLNode::Unlink( XMLNode* child )
642{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300643 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400667 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800668}
669
670
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
672{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300673 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300674 if ( addThis->_document != _document ) {
675 TIXMLASSERT( false );
676 return 0;
677 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800678 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700679
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 if ( _lastChild ) {
681 TIXMLASSERT( _firstChild );
682 TIXMLASSERT( _lastChild->_next == 0 );
683 _lastChild->_next = addThis;
684 addThis->_prev = _lastChild;
685 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
689 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( _firstChild == 0 );
691 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_prev = 0;
694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698}
699
700
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
702{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300703 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300704 if ( addThis->_document != _document ) {
705 TIXMLASSERT( false );
706 return 0;
707 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800708 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 if ( _firstChild ) {
711 TIXMLASSERT( _lastChild );
712 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 _firstChild->_prev = addThis;
715 addThis->_next = _firstChild;
716 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 }
720 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 TIXMLASSERT( _lastChild == 0 );
722 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 addThis->_prev = 0;
725 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400728 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729}
730
731
732XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
733{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300734 TIXMLASSERT( addThis );
735 if ( addThis->_document != _document ) {
736 TIXMLASSERT( false );
737 return 0;
738 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700739
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700741
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300743 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 return 0;
745 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 // The last node or the only node.
749 return InsertEndChild( addThis );
750 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800751 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 addThis->_prev = afterThis;
753 addThis->_next = afterThis->_next;
754 afterThis->_next->_prev = addThis;
755 afterThis->_next = addThis;
756 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800758}
759
760
761
762
Lee Thomason56bdd022012-02-09 18:16:58 -0800763const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 XMLElement* element = node->ToElement();
767 if ( element ) {
768 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
769 return element;
770 }
771 }
772 }
773 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800774}
775
776
Lee Thomason56bdd022012-02-09 18:16:58 -0800777const XMLElement* XMLNode::LastChildElement( const char* value ) const
778{
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 XMLElement* element = node->ToElement();
781 if ( element ) {
782 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
783 return element;
784 }
785 }
786 }
787 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800788}
789
790
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800791const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
792{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400793 for( XMLNode* node=this->_next; node; node = node->_next ) {
794 const XMLElement* element = node->ToElement();
795 if ( element
796 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
797 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
799 }
800 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800801}
802
803
804const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
805{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400806 for( XMLNode* node=_prev; node; node = node->_prev ) {
807 const XMLElement* element = node->ToElement();
808 if ( element
809 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
810 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
812 }
813 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800814}
815
816
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800817char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800818{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 // This is a recursive method, but thinking about it "at the current level"
820 // it is a pretty simple flat list:
821 // <foo/>
822 // <!-- comment -->
823 //
824 // With a special case:
825 // <foo>
826 // </foo>
827 // <!-- comment -->
828 //
829 // Where the closing element (/foo) *must* be the next thing after the opening
830 // element, and the names must match. BUT the tricky bit is that the closing
831 // element will be read by the child.
832 //
833 // 'endTag' is the end tag for this node, it is returned by a call to a child.
834 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 while( p && *p ) {
837 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 if ( p == 0 || node == 0 ) {
841 break;
842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 StrPair endTag;
845 p = node->ParseDeep( p, &endTag );
846 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400847 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 if ( !_document->Error() ) {
849 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 }
851 break;
852 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400854 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500856 // We read the end tag. Return it to the parent.
857 if ( ele->ClosingType() == XMLElement::CLOSING ) {
858 if ( parentEnd ) {
859 ele->_value.TransferTo( parentEnd );
860 }
861 node->_memPool->SetTracked(); // created and then immediately deleted.
862 DeleteNode( node );
863 return p;
864 }
865
866 // Handle an end tag returned to this level.
867 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400868 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300869 if ( endTag.Empty() ) {
870 if ( ele->ClosingType() == XMLElement::OPEN ) {
871 mismatch = true;
872 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300874 else {
875 if ( ele->ClosingType() != XMLElement::OPEN ) {
876 mismatch = true;
877 }
878 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400879 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400882 if ( mismatch ) {
883 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500884 DeleteNode( node );
885 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400886 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
JayXondbfdd8f2014-12-12 20:07:14 -0500888 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800891}
892
Dmitry-Mee3225b12014-09-03 11:03:11 +0400893void XMLNode::DeleteNode( XMLNode* node )
894{
895 if ( node == 0 ) {
896 return;
897 }
898 MemPool* pool = node->_memPool;
899 node->~XMLNode();
900 pool->Free( node );
901}
902
Lee Thomason3cebdc42015-01-05 17:16:28 -0800903void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300904{
905 TIXMLASSERT( insertThis );
906 TIXMLASSERT( insertThis->_document == _document );
907
908 if ( insertThis->_parent )
909 insertThis->_parent->Unlink( insertThis );
910 else
911 insertThis->_memPool->SetTracked();
912}
913
Lee Thomason5492a1c2012-01-23 15:32:10 -0800914// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800915char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800916{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 const char* start = p;
918 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 }
923 return p;
924 }
925 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700926 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
927 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 flags |= StrPair::COLLAPSE_WHITESPACE;
929 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700930
Lee Thomason624d43f2012-10-12 10:58:48 -0700931 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 if ( p && *p ) {
933 return p-1;
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300934 } else if ( !p ) {
935 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 }
937 }
938 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800939}
940
941
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
943{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
948 text->SetCData( this->CData() );
949 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800950}
951
952
953bool XMLText::ShallowEqual( const XMLNode* compare ) const
954{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400955 const XMLText* text = compare->ToText();
956 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957}
958
959
Lee Thomason56bdd022012-02-09 18:16:58 -0800960bool XMLText::Accept( XMLVisitor* visitor ) const
961{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300962 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800964}
965
966
Lee Thomason3f57d272012-01-11 15:30:03 -0800967// --------- XMLComment ---------- //
968
Lee Thomasone4422302012-01-20 17:59:50 -0800969XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800970{
971}
972
973
Lee Thomasonce0763e2012-01-11 15:43:54 -0800974XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800975{
Lee Thomason3f57d272012-01-11 15:30:03 -0800976}
977
978
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800979char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 // Comment parses as text.
982 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700985 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 }
987 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800988}
989
990
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800991XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
996 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
997 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998}
999
1000
1001bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1002{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001003 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001004 const XMLComment* comment = compare->ToComment();
1005 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001006}
1007
1008
Lee Thomason751da522012-02-10 08:50:51 -08001009bool XMLComment::Accept( XMLVisitor* visitor ) const
1010{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001011 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001013}
Lee Thomason56bdd022012-02-09 18:16:58 -08001014
1015
Lee Thomason50f97b22012-02-11 16:33:40 -08001016// --------- XMLDeclaration ---------- //
1017
1018XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1019{
1020}
1021
1022
1023XMLDeclaration::~XMLDeclaration()
1024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001026}
1027
1028
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001029char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001030{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 // Declaration parses as text.
1032 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001035 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 }
1037 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001038}
1039
1040
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001041XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1047 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001048}
1049
1050
1051bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1052{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001053 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001054 const XMLDeclaration* declaration = compare->ToDeclaration();
1055 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001056}
1057
1058
1059
Lee Thomason50f97b22012-02-11 16:33:40 -08001060bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1061{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001062 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
1066// --------- XMLUnknown ---------- //
1067
1068XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1069{
1070}
1071
1072
1073XMLUnknown::~XMLUnknown()
1074{
1075}
1076
1077
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001078char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Unknown parses as text.
1081 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001082
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 }
1087 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001088}
1089
1090
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001091XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1092{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001094 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 }
1096 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1097 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001098}
1099
1100
1101bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1102{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001103 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001104 const XMLUnknown* unknown = compare->ToUnknown();
1105 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001106}
1107
1108
Lee Thomason50f97b22012-02-11 16:33:40 -08001109bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1110{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001111 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001113}
1114
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001115// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001116
1117const char* XMLAttribute::Name() const
1118{
1119 return _name.GetStr();
1120}
1121
1122const char* XMLAttribute::Value() const
1123{
1124 return _value.GetStr();
1125}
1126
Lee Thomason6f381b72012-03-02 12:59:39 -08001127char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001130 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 if ( !p || !*p ) {
1132 return 0;
1133 }
Lee Thomason22aead12012-01-23 13:29:35 -08001134
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 // Skip white space before =
1136 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001137 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 return 0;
1139 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001140
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 ++p; // move up to opening quote
1142 p = XMLUtil::SkipWhiteSpace( p );
1143 if ( *p != '\"' && *p != '\'' ) {
1144 return 0;
1145 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001146
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 char endTag[2] = { *p, 0 };
1148 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001149
Lee Thomason624d43f2012-10-12 10:58:48 -07001150 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001152}
1153
1154
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001155void XMLAttribute::SetName( const char* n )
1156{
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001158}
1159
1160
Lee Thomason2fa81722012-11-09 12:37:46 -08001161XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 if ( XMLUtil::ToInt( Value(), value )) {
1164 return XML_NO_ERROR;
1165 }
1166 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167}
1168
1169
Lee Thomason2fa81722012-11-09 12:37:46 -08001170XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 if ( XMLUtil::ToUnsigned( Value(), value )) {
1173 return XML_NO_ERROR;
1174 }
1175 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176}
1177
1178
Lee Thomason2fa81722012-11-09 12:37:46 -08001179XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 if ( XMLUtil::ToBool( Value(), value )) {
1182 return XML_NO_ERROR;
1183 }
1184 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185}
1186
1187
Lee Thomason2fa81722012-11-09 12:37:46 -08001188XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 if ( XMLUtil::ToFloat( Value(), value )) {
1191 return XML_NO_ERROR;
1192 }
1193 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001194}
1195
1196
Lee Thomason2fa81722012-11-09 12:37:46 -08001197XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 if ( XMLUtil::ToDouble( Value(), value )) {
1200 return XML_NO_ERROR;
1201 }
1202 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001203}
1204
1205
1206void XMLAttribute::SetAttribute( const char* v )
1207{
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001209}
1210
1211
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212void XMLAttribute::SetAttribute( int v )
1213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 char buf[BUF_SIZE];
1215 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218
1219
1220void XMLAttribute::SetAttribute( unsigned v )
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 char buf[BUF_SIZE];
1223 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001225}
1226
1227
1228void XMLAttribute::SetAttribute( bool v )
1229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 char buf[BUF_SIZE];
1231 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001232 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001233}
1234
1235void XMLAttribute::SetAttribute( double v )
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 char buf[BUF_SIZE];
1238 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242void XMLAttribute::SetAttribute( float v )
1243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 char buf[BUF_SIZE];
1245 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001246 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001247}
1248
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001249
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001250// --------- XMLElement ---------- //
1251XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001252 _closingType( 0 ),
1253 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001254{
1255}
1256
1257
1258XMLElement::~XMLElement()
1259{
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 while( _rootAttribute ) {
1261 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001262 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001265}
1266
1267
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001268const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1269{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001270 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1272 return a;
1273 }
1274 }
1275 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001276}
1277
1278
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001279const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 const XMLAttribute* a = FindAttribute( name );
1282 if ( !a ) {
1283 return 0;
1284 }
1285 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1286 return a->Value();
1287 }
1288 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001289}
1290
1291
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001292const char* XMLElement::GetText() const
1293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001295 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 }
1297 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001298}
1299
1300
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001301void XMLElement::SetText( const char* inText )
1302{
Uli Kusterer869bb592014-01-21 01:36:16 +01001303 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001304 FirstChild()->SetValue( inText );
1305 else {
1306 XMLText* theText = GetDocument()->NewText( inText );
1307 InsertFirstChild( theText );
1308 }
1309}
1310
Lee Thomason5bb2d802014-01-24 10:42:57 -08001311
1312void XMLElement::SetText( int v )
1313{
1314 char buf[BUF_SIZE];
1315 XMLUtil::ToStr( v, buf, BUF_SIZE );
1316 SetText( buf );
1317}
1318
1319
1320void XMLElement::SetText( unsigned v )
1321{
1322 char buf[BUF_SIZE];
1323 XMLUtil::ToStr( v, buf, BUF_SIZE );
1324 SetText( buf );
1325}
1326
1327
1328void XMLElement::SetText( bool v )
1329{
1330 char buf[BUF_SIZE];
1331 XMLUtil::ToStr( v, buf, BUF_SIZE );
1332 SetText( buf );
1333}
1334
1335
1336void XMLElement::SetText( float v )
1337{
1338 char buf[BUF_SIZE];
1339 XMLUtil::ToStr( v, buf, BUF_SIZE );
1340 SetText( buf );
1341}
1342
1343
1344void XMLElement::SetText( double v )
1345{
1346 char buf[BUF_SIZE];
1347 XMLUtil::ToStr( v, buf, BUF_SIZE );
1348 SetText( buf );
1349}
1350
1351
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001355 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return XML_SUCCESS;
1358 }
1359 return XML_CAN_NOT_CONVERT_TEXT;
1360 }
1361 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001362}
1363
1364
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001368 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return XML_SUCCESS;
1371 }
1372 return XML_CAN_NOT_CONVERT_TEXT;
1373 }
1374 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001375}
1376
1377
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001381 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 return XML_SUCCESS;
1384 }
1385 return XML_CAN_NOT_CONVERT_TEXT;
1386 }
1387 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001388}
1389
1390
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001392{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001394 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 return XML_SUCCESS;
1397 }
1398 return XML_CAN_NOT_CONVERT_TEXT;
1399 }
1400 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001401}
1402
1403
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001407 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 return XML_SUCCESS;
1410 }
1411 return XML_CAN_NOT_CONVERT_TEXT;
1412 }
1413 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001414}
1415
1416
1417
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001418XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 XMLAttribute* last = 0;
1421 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1426 break;
1427 }
1428 }
1429 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001430 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1432 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 }
1436 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
1439 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001440 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 }
1442 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001443}
1444
1445
U-Stream\Leeae25a442012-02-17 17:48:16 -08001446void XMLElement::DeleteAttribute( const char* name )
1447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1451 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 }
1454 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001455 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001457 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 break;
1459 }
1460 prev = a;
1461 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001462}
1463
1464
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001465char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 const char* start = p;
1468 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001469
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 // Read the attributes.
1471 while( p ) {
1472 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001473 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 return 0;
1476 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001477
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001479 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001480 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1482 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001483 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001484
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001487 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 return 0;
1490 }
1491 // There is a minor bug here: if the attribute in the source xml
1492 // document is duplicated, it will not be detected and the
1493 // attribute will be doubly added. However, tracking the 'prevAttribute'
1494 // avoids re-scanning the attribute list. Preferring performance for
1495 // now, may reconsider in the future.
1496 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 }
1499 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
1502 prevAttribute = attrib;
1503 }
1504 // end of the tag
1505 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 return p+2; // done; sealed element.
1508 }
1509 // end of the tag
1510 else if ( *p == '>' ) {
1511 ++p;
1512 break;
1513 }
1514 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 return 0;
1517 }
1518 }
1519 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001520}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001521
Dmitry-Mee3225b12014-09-03 11:03:11 +04001522void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1523{
1524 if ( attribute == 0 ) {
1525 return;
1526 }
1527 MemPool* pool = attribute->_memPool;
1528 attribute->~XMLAttribute();
1529 pool->Free( attribute );
1530}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001531
Lee Thomason67d61312012-01-24 16:01:51 -08001532//
1533// <ele></ele>
1534// <ele>foo<b>bar</b></ele>
1535//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001536char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 // Read the element name.
1539 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001540
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 // The closing element is the </element> form. It is
1542 // parsed just like a regular element then deleted from
1543 // the DOM.
1544 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 ++p;
1547 }
Lee Thomason67d61312012-01-24 16:01:51 -08001548
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 p = _value.ParseName( p );
1550 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 return 0;
1552 }
Lee Thomason67d61312012-01-24 16:01:51 -08001553
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001555 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 return p;
1557 }
Lee Thomason67d61312012-01-24 16:01:51 -08001558
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 p = XMLNode::ParseDeep( p, strPair );
1560 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001561}
1562
1563
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001564
1565XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 }
1570 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1571 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1572 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1573 }
1574 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001575}
1576
1577
1578bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1579{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001580 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 const XMLElement* other = compare->ToElement();
1582 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001583
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 const XMLAttribute* a=FirstAttribute();
1585 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001586
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 while ( a && b ) {
1588 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1589 return false;
1590 }
1591 a = a->Next();
1592 b = b->Next();
1593 }
1594 if ( a || b ) {
1595 // different count
1596 return false;
1597 }
1598 return true;
1599 }
1600 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001601}
1602
1603
Lee Thomason751da522012-02-10 08:50:51 -08001604bool XMLElement::Accept( XMLVisitor* visitor ) const
1605{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001606 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1609 if ( !node->Accept( visitor ) ) {
1610 break;
1611 }
1612 }
1613 }
1614 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001615}
Lee Thomason56bdd022012-02-09 18:16:58 -08001616
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001617
Lee Thomason3f57d272012-01-11 15:30:03 -08001618// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001619
1620// Warning: List must match 'enum XMLError'
1621const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1622 "XML_SUCCESS",
1623 "XML_NO_ATTRIBUTE",
1624 "XML_WRONG_ATTRIBUTE_TYPE",
1625 "XML_ERROR_FILE_NOT_FOUND",
1626 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1627 "XML_ERROR_FILE_READ_ERROR",
1628 "XML_ERROR_ELEMENT_MISMATCH",
1629 "XML_ERROR_PARSING_ELEMENT",
1630 "XML_ERROR_PARSING_ATTRIBUTE",
1631 "XML_ERROR_IDENTIFYING_TAG",
1632 "XML_ERROR_PARSING_TEXT",
1633 "XML_ERROR_PARSING_CDATA",
1634 "XML_ERROR_PARSING_COMMENT",
1635 "XML_ERROR_PARSING_DECLARATION",
1636 "XML_ERROR_PARSING_UNKNOWN",
1637 "XML_ERROR_EMPTY_DOCUMENT",
1638 "XML_ERROR_MISMATCHED_ELEMENT",
1639 "XML_ERROR_PARSING",
1640 "XML_CAN_NOT_CONVERT_TEXT",
1641 "XML_NO_TEXT_NODE"
1642};
1643
1644
Lee Thomason624d43f2012-10-12 10:58:48 -07001645XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001647 _writeBOM( false ),
1648 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001649 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _whitespace( whitespace ),
1651 _errorStr1( 0 ),
1652 _errorStr2( 0 ),
1653 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001654{
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001656}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001657
1658
Lee Thomason3f57d272012-01-11 15:30:03 -08001659XMLDocument::~XMLDocument()
1660{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001661 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001662}
1663
1664
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001665void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001666{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001667 DeleteChildren();
1668
Dmitry-Meab37df82014-11-28 12:08:36 +03001669#ifdef DEBUG
1670 const bool hadError = Error();
1671#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 _errorID = XML_NO_ERROR;
1673 _errorStr1 = 0;
1674 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001675
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 delete [] _charBuffer;
1677 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001678
1679#if 0
1680 _textPool.Trace( "text" );
1681 _elementPool.Trace( "element" );
1682 _commentPool.Trace( "comment" );
1683 _attributePool.Trace( "attribute" );
1684#endif
1685
1686#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001687 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001688 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1689 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1690 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1691 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1692 }
1693#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001694}
1695
Lee Thomason3f57d272012-01-11 15:30:03 -08001696
Lee Thomason2c85a712012-01-31 08:24:24 -08001697XMLElement* XMLDocument::NewElement( const char* name )
1698{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001699 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1701 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001702 ele->SetName( name );
1703 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001704}
1705
1706
Lee Thomason1ff38e02012-02-14 18:18:16 -08001707XMLComment* XMLDocument::NewComment( const char* str )
1708{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001709 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1711 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 comment->SetValue( str );
1713 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001714}
1715
1716
1717XMLText* XMLDocument::NewText( const char* str )
1718{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001719 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1721 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 text->SetValue( str );
1723 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001724}
1725
1726
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001727XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1728{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001729 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1731 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1733 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001734}
1735
1736
1737XMLUnknown* XMLDocument::NewUnknown( const char* str )
1738{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001739 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1741 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 unk->SetValue( str );
1743 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001744}
1745
Dmitry-Me01578db2014-08-19 10:18:48 +04001746static FILE* callfopen( const char* filepath, const char* mode )
1747{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001748 TIXMLASSERT( filepath );
1749 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001750#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1751 FILE* fp = 0;
1752 errno_t err = fopen_s( &fp, filepath, mode );
1753 if ( err ) {
1754 return 0;
1755 }
1756#else
1757 FILE* fp = fopen( filepath, mode );
1758#endif
1759 return fp;
1760}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001761
1762void XMLDocument::DeleteNode( XMLNode* node ) {
1763 TIXMLASSERT( node );
1764 TIXMLASSERT(node->_document == this );
1765 if (node->_parent) {
1766 node->_parent->DeleteChild( node );
1767 }
1768 else {
1769 // Isn't in the tree.
1770 // Use the parent delete.
1771 // Also, we need to mark it tracked: we 'know'
1772 // it was never used.
1773 node->_memPool->SetTracked();
1774 // Call the static XMLNode version:
1775 XMLNode::DeleteNode(node);
1776 }
1777}
1778
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001779
Lee Thomason2fa81722012-11-09 12:37:46 -08001780XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001781{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001782 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001783 FILE* fp = callfopen( filename, "rb" );
1784 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 }
1788 LoadFile( fp );
1789 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001791}
1792
1793
Lee Thomason2fa81722012-11-09 12:37:46 -08001794XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001796 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001797
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001798 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001799 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001800 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1801 return _errorID;
1802 }
1803
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001805 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001807 if ( filelength == -1L ) {
1808 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1809 return _errorID;
1810 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001811
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001812 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001814 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001817
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 _charBuffer = new char[size+1];
1819 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 if ( read != size ) {
1821 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001824
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826
Dmitry-Me97476b72015-01-01 16:15:57 +03001827 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829}
1830
1831
Lee Thomason2fa81722012-11-09 12:37:46 -08001832XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833{
Dmitry-Me01578db2014-08-19 10:18:48 +04001834 FILE* fp = callfopen( filename, "w" );
1835 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 }
1839 SaveFile(fp, compact);
1840 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001842}
1843
1844
Lee Thomason2fa81722012-11-09 12:37:46 -08001845XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001846{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 XMLPrinter stream( fp, compact );
1848 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001850}
1851
Lee Thomason1ff38e02012-02-14 18:18:16 -08001852
Lee Thomason2fa81722012-11-09 12:37:46 -08001853XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001854{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001855 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001856
Lee Thomason82d32002014-02-21 22:47:18 -08001857 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
1861 if ( len == (size_t)(-1) ) {
1862 len = strlen( p );
1863 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 _charBuffer = new char[ len+1 ];
1865 memcpy( _charBuffer, p, len );
1866 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001867
Dmitry-Me97476b72015-01-01 16:15:57 +03001868 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001869 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001870 // clean up now essentially dangling memory.
1871 // and the parse fail can put objects in the
1872 // pools that are dead and inaccessible.
1873 DeleteChildren();
1874 _elementPool.Clear();
1875 _attributePool.Clear();
1876 _textPool.Clear();
1877 _commentPool.Clear();
1878 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001880}
1881
1882
PKEuS1c5f99e2013-07-06 11:28:39 +02001883void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001884{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 XMLPrinter stdStreamer( stdout );
1886 if ( !streamer ) {
1887 streamer = &stdStreamer;
1888 }
1889 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001890}
1891
1892
Lee Thomason2fa81722012-11-09 12:37:46 -08001893void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001894{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001895 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 _errorID = error;
1897 _errorStr1 = str1;
1898 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001899}
1900
Lee Thomason331596e2014-09-11 14:56:43 -07001901const char* XMLDocument::ErrorName() const
1902{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001903 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001904 return _errorNames[_errorID];
1905}
Lee Thomason5cae8972012-01-24 18:03:07 -08001906
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001907void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001908{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001909 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 static const int LEN = 20;
1911 char buf1[LEN] = { 0 };
1912 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001913
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 if ( _errorStr1 ) {
1915 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 if ( _errorStr2 ) {
1918 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001920
Lee Thomason331596e2014-09-11 14:56:43 -07001921 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1922 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001924}
1925
Dmitry-Me97476b72015-01-01 16:15:57 +03001926void XMLDocument::Parse()
1927{
1928 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1929 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001930 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001931 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001932 p = (char*) XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Me97476b72015-01-01 16:15:57 +03001933 if ( !*p ) {
1934 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1935 return;
1936 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001937 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001938}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001939
PKEuS1bfb9542013-08-04 13:51:17 +02001940XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 _elementJustOpened( false ),
1942 _firstElement( true ),
1943 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001944 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 _textDepth( -1 ),
1946 _processEntities( true ),
1947 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _entityFlag[i] = false;
1951 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 }
1953 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001954 const char entityValue = entities[i].value;
1955 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1956 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001958 _restrictedEntityFlag[(unsigned char)'&'] = true;
1959 _restrictedEntityFlag[(unsigned char)'<'] = true;
1960 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001962}
1963
1964
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001965void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001966{
1967 va_list va;
1968 va_start( va, format );
1969
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 if ( _fp ) {
1971 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 }
1973 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001974#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001975 #if defined(WINCE)
1976 int len = 512;
1977 do {
1978 len = len*2;
1979 char* str = new char[len]();
1980 len = _vsnprintf(str, len, format, va);
1981 delete[] str;
1982 }while (len < 0);
1983 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001984 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001985 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986#else
1987 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001988#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 // Close out and re-start the va-args
1990 va_end( va );
1991 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001992 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1993#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001994 #if defined(WINCE)
1995 _vsnprintf( p, len+1, format, va );
1996 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001997 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001998 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001999#else
2000 vsnprintf( p, len+1, format, va );
2001#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002003 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002004}
2005
2006
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002007void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 for( int i=0; i<depth; ++i ) {
2010 Print( " " );
2011 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002012}
2013
2014
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002015void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 // Look for runs of bytes between entities to print.
2018 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002020
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 while ( *q ) {
2023 // Remember, char is sometimes signed. (How many times has that bitten me?)
2024 if ( *q > 0 && *q < ENTITY_RANGE ) {
2025 // Check for entities. If one is found, flush
2026 // the stream up until the entity, write the
2027 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002028 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 while ( p < q ) {
2030 Print( "%c", *p );
2031 ++p;
2032 }
2033 for( int i=0; i<NUM_ENTITIES; ++i ) {
2034 if ( entities[i].value == *q ) {
2035 Print( "&%s;", entities[i].pattern );
2036 break;
2037 }
2038 }
2039 ++p;
2040 }
2041 }
2042 ++q;
2043 }
2044 }
2045 // Flush the remaining string. This will be the entire
2046 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002047 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 Print( "%s", p );
2049 }
Lee Thomason857b8682012-01-25 17:50:25 -08002050}
2051
U-Stream\Leeae25a442012-02-17 17:48:16 -08002052
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002053void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002054{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002056 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 -07002057 Print( "%s", bom );
2058 }
2059 if ( writeDec ) {
2060 PushDeclaration( "xml version=\"1.0\"" );
2061 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002062}
2063
2064
Uli Kusterer593a33d2014-02-01 12:48:51 +01002065void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002066{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002067 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002069
Uli Kusterer593a33d2014-02-01 12:48:51 +01002070 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002072 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002073 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002076
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _elementJustOpened = true;
2079 _firstElement = false;
2080 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002081}
2082
2083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002085{
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 Print( " %s=\"", name );
2088 PrintString( value, false );
2089 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002090}
2091
2092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002093void XMLPrinter::PushAttribute( const char* name, int v )
2094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 char buf[BUF_SIZE];
2096 XMLUtil::ToStr( v, buf, BUF_SIZE );
2097 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002098}
2099
2100
2101void XMLPrinter::PushAttribute( const char* name, unsigned v )
2102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 char buf[BUF_SIZE];
2104 XMLUtil::ToStr( v, buf, BUF_SIZE );
2105 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002106}
2107
2108
2109void XMLPrinter::PushAttribute( const char* name, bool v )
2110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 char buf[BUF_SIZE];
2112 XMLUtil::ToStr( v, buf, BUF_SIZE );
2113 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
2116
2117void XMLPrinter::PushAttribute( const char* name, double v )
2118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( v, buf, BUF_SIZE );
2121 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
2124
Uli Kustererca412e82014-02-01 13:35:05 +01002125void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002126{
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 --_depth;
2128 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002129
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 Print( "/>" );
2132 }
2133 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002134 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
2138 Print( "</%s>", name );
2139 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002140
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _textDepth == _depth ) {
2142 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Uli Kustererca412e82014-02-01 13:35:05 +01002144 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 Print( "\n" );
2146 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002148}
2149
2150
Dmitry-Mea092bc12014-12-23 17:57:05 +03002151void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002152{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002153 if ( !_elementJustOpened ) {
2154 return;
2155 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002158}
2159
2160
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002161void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002162{
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002164
Dmitry-Mea092bc12014-12-23 17:57:05 +03002165 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 if ( cdata ) {
2167 Print( "<![CDATA[" );
2168 Print( "%s", text );
2169 Print( "]]>" );
2170 }
2171 else {
2172 PrintString( text, true );
2173 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002174}
2175
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002176void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 char buf[BUF_SIZE];
2179 XMLUtil::ToStr( value, buf, BUF_SIZE );
2180 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002181}
2182
2183
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002184void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 char buf[BUF_SIZE];
2187 XMLUtil::ToStr( value, buf, BUF_SIZE );
2188 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002189}
2190
2191
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002192void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 char buf[BUF_SIZE];
2195 XMLUtil::ToStr( value, buf, BUF_SIZE );
2196 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002197}
2198
2199
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002200void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 char buf[BUF_SIZE];
2203 XMLUtil::ToStr( value, buf, BUF_SIZE );
2204 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002205}
2206
2207
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002208void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 char buf[BUF_SIZE];
2211 XMLUtil::ToStr( value, buf, BUF_SIZE );
2212 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002213}
2214
Lee Thomason5cae8972012-01-24 18:03:07 -08002215
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002216void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002217{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002218 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002225}
Lee Thomason751da522012-02-10 08:50:51 -08002226
2227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002230 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002242 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002249}
2250
2251
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002252bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002253{
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 if ( doc.HasBOM() ) {
2256 PushHeader( true, false );
2257 }
2258 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002259}
2260
2261
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002262bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002263{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002264 const XMLElement* parentElem = element.Parent()->ToElement();
2265 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2266 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 while ( attribute ) {
2268 PushAttribute( attribute->Name(), attribute->Value() );
2269 attribute = attribute->Next();
2270 }
2271 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002272}
2273
2274
Uli Kustererca412e82014-02-01 13:35:05 +01002275bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002276{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002277 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002279}
2280
2281
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002282bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 PushText( text.Value(), text.CData() );
2285 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002286}
2287
2288
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002289bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 PushComment( comment.Value() );
2292 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002293}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002295bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 PushDeclaration( declaration.Value() );
2298 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299}
2300
2301
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002302bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 PushUnknown( unknown.Value() );
2305 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002307
Lee Thomason685b8952012-11-12 13:00:06 -08002308} // namespace tinyxml2
2309