blob: 90b9e7945b53b499caff51ad9b930fd0241db73b [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-Me257e11b2015-01-09 15:50:47 +0300934 }
935 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300936 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 }
938 }
939 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800940}
941
942
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800943XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
944{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 }
948 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
949 text->SetCData( this->CData() );
950 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951}
952
953
954bool XMLText::ShallowEqual( const XMLNode* compare ) const
955{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400956 const XMLText* text = compare->ToText();
957 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958}
959
960
Lee Thomason56bdd022012-02-09 18:16:58 -0800961bool XMLText::Accept( XMLVisitor* visitor ) const
962{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300963 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800965}
966
967
Lee Thomason3f57d272012-01-11 15:30:03 -0800968// --------- XMLComment ---------- //
969
Lee Thomasone4422302012-01-20 17:59:50 -0800970XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800971{
972}
973
974
Lee Thomasonce0763e2012-01-11 15:43:54 -0800975XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800976{
Lee Thomason3f57d272012-01-11 15:30:03 -0800977}
978
979
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800980char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 // Comment parses as text.
983 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700984 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700986 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 }
988 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800989}
990
991
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800992XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700995 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 }
997 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
998 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999}
1000
1001
1002bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1003{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001004 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001005 const XMLComment* comment = compare->ToComment();
1006 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
Lee Thomason751da522012-02-10 08:50:51 -08001010bool XMLComment::Accept( XMLVisitor* visitor ) const
1011{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001012 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001014}
Lee Thomason56bdd022012-02-09 18:16:58 -08001015
1016
Lee Thomason50f97b22012-02-11 16:33:40 -08001017// --------- XMLDeclaration ---------- //
1018
1019XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1020{
1021}
1022
1023
1024XMLDeclaration::~XMLDeclaration()
1025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001026 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001027}
1028
1029
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001030char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 // Declaration parses as text.
1033 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001034 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 }
1038 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001039}
1040
1041
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001042XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1043{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 }
1047 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1048 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001049}
1050
1051
1052bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1053{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001054 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001055 const XMLDeclaration* declaration = compare->ToDeclaration();
1056 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1062{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001063 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001065}
1066
1067// --------- XMLUnknown ---------- //
1068
1069XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1070{
1071}
1072
1073
1074XMLUnknown::~XMLUnknown()
1075{
1076}
1077
1078
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001079char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 // Unknown parses as text.
1082 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001083
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 }
1088 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001089}
1090
1091
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001095 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 }
1097 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1098 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001099}
1100
1101
1102bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1103{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001104 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001105 const XMLUnknown* unknown = compare->ToUnknown();
1106 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001107}
1108
1109
Lee Thomason50f97b22012-02-11 16:33:40 -08001110bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1111{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001112 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001114}
1115
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001116// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001117
1118const char* XMLAttribute::Name() const
1119{
1120 return _name.GetStr();
1121}
1122
1123const char* XMLAttribute::Value() const
1124{
1125 return _value.GetStr();
1126}
1127
Lee Thomason6f381b72012-03-02 12:59:39 -08001128char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( !p || !*p ) {
1133 return 0;
1134 }
Lee Thomason22aead12012-01-23 13:29:35 -08001135
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 // Skip white space before =
1137 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001138 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 return 0;
1140 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001141
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 ++p; // move up to opening quote
1143 p = XMLUtil::SkipWhiteSpace( p );
1144 if ( *p != '\"' && *p != '\'' ) {
1145 return 0;
1146 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001147
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 char endTag[2] = { *p, 0 };
1149 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001150
Lee Thomason624d43f2012-10-12 10:58:48 -07001151 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001153}
1154
1155
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001156void XMLAttribute::SetName( const char* n )
1157{
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001159}
1160
1161
Lee Thomason2fa81722012-11-09 12:37:46 -08001162XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 if ( XMLUtil::ToInt( Value(), value )) {
1165 return XML_NO_ERROR;
1166 }
1167 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
1169
1170
Lee Thomason2fa81722012-11-09 12:37:46 -08001171XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 if ( XMLUtil::ToUnsigned( Value(), value )) {
1174 return XML_NO_ERROR;
1175 }
1176 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001177}
1178
1179
Lee Thomason2fa81722012-11-09 12:37:46 -08001180XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 if ( XMLUtil::ToBool( Value(), value )) {
1183 return XML_NO_ERROR;
1184 }
1185 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001186}
1187
1188
Lee Thomason2fa81722012-11-09 12:37:46 -08001189XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 if ( XMLUtil::ToFloat( Value(), value )) {
1192 return XML_NO_ERROR;
1193 }
1194 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001195}
1196
1197
Lee Thomason2fa81722012-11-09 12:37:46 -08001198XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( XMLUtil::ToDouble( Value(), value )) {
1201 return XML_NO_ERROR;
1202 }
1203 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001204}
1205
1206
1207void XMLAttribute::SetAttribute( const char* v )
1208{
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210}
1211
1212
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213void XMLAttribute::SetAttribute( int v )
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 char buf[BUF_SIZE];
1216 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219
1220
1221void XMLAttribute::SetAttribute( unsigned v )
1222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 char buf[BUF_SIZE];
1224 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001226}
1227
1228
1229void XMLAttribute::SetAttribute( bool v )
1230{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 char buf[BUF_SIZE];
1232 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001234}
1235
1236void XMLAttribute::SetAttribute( double v )
1237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 char buf[BUF_SIZE];
1239 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241}
1242
1243void XMLAttribute::SetAttribute( float v )
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 char buf[BUF_SIZE];
1246 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001250
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001251// --------- XMLElement ---------- //
1252XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001253 _closingType( 0 ),
1254 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001255{
1256}
1257
1258
1259XMLElement::~XMLElement()
1260{
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 while( _rootAttribute ) {
1262 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001263 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001266}
1267
1268
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001269const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1270{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001271 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1273 return a;
1274 }
1275 }
1276 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001277}
1278
1279
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001280const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 const XMLAttribute* a = FindAttribute( name );
1283 if ( !a ) {
1284 return 0;
1285 }
1286 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1287 return a->Value();
1288 }
1289 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001290}
1291
1292
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001293const char* XMLElement::GetText() const
1294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001296 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 }
1298 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001299}
1300
1301
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001302void XMLElement::SetText( const char* inText )
1303{
Uli Kusterer869bb592014-01-21 01:36:16 +01001304 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001305 FirstChild()->SetValue( inText );
1306 else {
1307 XMLText* theText = GetDocument()->NewText( inText );
1308 InsertFirstChild( theText );
1309 }
1310}
1311
Lee Thomason5bb2d802014-01-24 10:42:57 -08001312
1313void XMLElement::SetText( int v )
1314{
1315 char buf[BUF_SIZE];
1316 XMLUtil::ToStr( v, buf, BUF_SIZE );
1317 SetText( buf );
1318}
1319
1320
1321void XMLElement::SetText( unsigned v )
1322{
1323 char buf[BUF_SIZE];
1324 XMLUtil::ToStr( v, buf, BUF_SIZE );
1325 SetText( buf );
1326}
1327
1328
1329void XMLElement::SetText( bool v )
1330{
1331 char buf[BUF_SIZE];
1332 XMLUtil::ToStr( v, buf, BUF_SIZE );
1333 SetText( buf );
1334}
1335
1336
1337void XMLElement::SetText( float v )
1338{
1339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
1341 SetText( buf );
1342}
1343
1344
1345void XMLElement::SetText( double v )
1346{
1347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
1349 SetText( buf );
1350}
1351
1352
MortenMacFly4ee49f12013-01-14 20:03:14 +01001353XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001356 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return XML_SUCCESS;
1359 }
1360 return XML_CAN_NOT_CONVERT_TEXT;
1361 }
1362 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001363}
1364
1365
MortenMacFly4ee49f12013-01-14 20:03:14 +01001366XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001369 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 return XML_SUCCESS;
1372 }
1373 return XML_CAN_NOT_CONVERT_TEXT;
1374 }
1375 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001376}
1377
1378
MortenMacFly4ee49f12013-01-14 20:03:14 +01001379XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001382 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001383 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 return XML_SUCCESS;
1385 }
1386 return XML_CAN_NOT_CONVERT_TEXT;
1387 }
1388 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001389}
1390
1391
MortenMacFly4ee49f12013-01-14 20:03:14 +01001392XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001395 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001396 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 return XML_SUCCESS;
1398 }
1399 return XML_CAN_NOT_CONVERT_TEXT;
1400 }
1401 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001402}
1403
1404
MortenMacFly4ee49f12013-01-14 20:03:14 +01001405XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001408 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001409 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 return XML_SUCCESS;
1411 }
1412 return XML_CAN_NOT_CONVERT_TEXT;
1413 }
1414 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001415}
1416
1417
1418
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001419XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 XMLAttribute* last = 0;
1422 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1427 break;
1428 }
1429 }
1430 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001431 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1433 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001441 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 }
1443 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001444}
1445
1446
U-Stream\Leeae25a442012-02-17 17:48:16 -08001447void XMLElement::DeleteAttribute( const char* name )
1448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1452 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
1455 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001458 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 break;
1460 }
1461 prev = a;
1462 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001463}
1464
1465
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001466char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 const char* start = p;
1469 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001470
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 // Read the attributes.
1472 while( p ) {
1473 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001474 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 return 0;
1477 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001478
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001480 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001481 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1483 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001484 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001485
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001488 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 return 0;
1491 }
1492 // There is a minor bug here: if the attribute in the source xml
1493 // document is duplicated, it will not be detected and the
1494 // attribute will be doubly added. However, tracking the 'prevAttribute'
1495 // avoids re-scanning the attribute list. Preferring performance for
1496 // now, may reconsider in the future.
1497 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 }
1500 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 }
1503 prevAttribute = attrib;
1504 }
1505 // end of the tag
1506 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 return p+2; // done; sealed element.
1509 }
1510 // end of the tag
1511 else if ( *p == '>' ) {
1512 ++p;
1513 break;
1514 }
1515 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 return 0;
1518 }
1519 }
1520 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001521}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001522
Dmitry-Mee3225b12014-09-03 11:03:11 +04001523void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1524{
1525 if ( attribute == 0 ) {
1526 return;
1527 }
1528 MemPool* pool = attribute->_memPool;
1529 attribute->~XMLAttribute();
1530 pool->Free( attribute );
1531}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001532
Lee Thomason67d61312012-01-24 16:01:51 -08001533//
1534// <ele></ele>
1535// <ele>foo<b>bar</b></ele>
1536//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001537char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 // Read the element name.
1540 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001541
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // The closing element is the </element> form. It is
1543 // parsed just like a regular element then deleted from
1544 // the DOM.
1545 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 ++p;
1548 }
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 p = _value.ParseName( p );
1551 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return 0;
1553 }
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 return p;
1558 }
Lee Thomason67d61312012-01-24 16:01:51 -08001559
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 p = XMLNode::ParseDeep( p, strPair );
1561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001562}
1563
1564
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565
1566XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1572 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1573 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1574 }
1575 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001576}
1577
1578
1579bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1580{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001581 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 const XMLElement* other = compare->ToElement();
1583 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001584
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 const XMLAttribute* a=FirstAttribute();
1586 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 while ( a && b ) {
1589 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1590 return false;
1591 }
1592 a = a->Next();
1593 b = b->Next();
1594 }
1595 if ( a || b ) {
1596 // different count
1597 return false;
1598 }
1599 return true;
1600 }
1601 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001602}
1603
1604
Lee Thomason751da522012-02-10 08:50:51 -08001605bool XMLElement::Accept( XMLVisitor* visitor ) const
1606{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001607 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1610 if ( !node->Accept( visitor ) ) {
1611 break;
1612 }
1613 }
1614 }
1615 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001616}
Lee Thomason56bdd022012-02-09 18:16:58 -08001617
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001618
Lee Thomason3f57d272012-01-11 15:30:03 -08001619// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001620
1621// Warning: List must match 'enum XMLError'
1622const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1623 "XML_SUCCESS",
1624 "XML_NO_ATTRIBUTE",
1625 "XML_WRONG_ATTRIBUTE_TYPE",
1626 "XML_ERROR_FILE_NOT_FOUND",
1627 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1628 "XML_ERROR_FILE_READ_ERROR",
1629 "XML_ERROR_ELEMENT_MISMATCH",
1630 "XML_ERROR_PARSING_ELEMENT",
1631 "XML_ERROR_PARSING_ATTRIBUTE",
1632 "XML_ERROR_IDENTIFYING_TAG",
1633 "XML_ERROR_PARSING_TEXT",
1634 "XML_ERROR_PARSING_CDATA",
1635 "XML_ERROR_PARSING_COMMENT",
1636 "XML_ERROR_PARSING_DECLARATION",
1637 "XML_ERROR_PARSING_UNKNOWN",
1638 "XML_ERROR_EMPTY_DOCUMENT",
1639 "XML_ERROR_MISMATCHED_ELEMENT",
1640 "XML_ERROR_PARSING",
1641 "XML_CAN_NOT_CONVERT_TEXT",
1642 "XML_NO_TEXT_NODE"
1643};
1644
1645
Lee Thomason624d43f2012-10-12 10:58:48 -07001646XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 _writeBOM( false ),
1649 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001650 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _whitespace( whitespace ),
1652 _errorStr1( 0 ),
1653 _errorStr2( 0 ),
1654 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655{
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001657}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001658
1659
Lee Thomason3f57d272012-01-11 15:30:03 -08001660XMLDocument::~XMLDocument()
1661{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001662 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001663}
1664
1665
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001667{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001668 DeleteChildren();
1669
Dmitry-Meab37df82014-11-28 12:08:36 +03001670#ifdef DEBUG
1671 const bool hadError = Error();
1672#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _errorID = XML_NO_ERROR;
1674 _errorStr1 = 0;
1675 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001676
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 delete [] _charBuffer;
1678 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001679
1680#if 0
1681 _textPool.Trace( "text" );
1682 _elementPool.Trace( "element" );
1683 _commentPool.Trace( "comment" );
1684 _attributePool.Trace( "attribute" );
1685#endif
1686
1687#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001688 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001689 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1690 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1691 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1692 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1693 }
1694#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001695}
1696
Lee Thomason3f57d272012-01-11 15:30:03 -08001697
Lee Thomason2c85a712012-01-31 08:24:24 -08001698XMLElement* XMLDocument::NewElement( const char* name )
1699{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001700 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1702 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 ele->SetName( name );
1704 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001705}
1706
1707
Lee Thomason1ff38e02012-02-14 18:18:16 -08001708XMLComment* XMLDocument::NewComment( const char* str )
1709{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001710 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1712 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 comment->SetValue( str );
1714 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001715}
1716
1717
1718XMLText* XMLDocument::NewText( const char* str )
1719{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001720 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1722 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 text->SetValue( str );
1724 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001725}
1726
1727
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001728XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1729{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001730 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1732 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1734 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001735}
1736
1737
1738XMLUnknown* XMLDocument::NewUnknown( const char* str )
1739{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001740 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1742 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 unk->SetValue( str );
1744 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001745}
1746
Dmitry-Me01578db2014-08-19 10:18:48 +04001747static FILE* callfopen( const char* filepath, const char* mode )
1748{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001749 TIXMLASSERT( filepath );
1750 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001751#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1752 FILE* fp = 0;
1753 errno_t err = fopen_s( &fp, filepath, mode );
1754 if ( err ) {
1755 return 0;
1756 }
1757#else
1758 FILE* fp = fopen( filepath, mode );
1759#endif
1760 return fp;
1761}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001762
1763void XMLDocument::DeleteNode( XMLNode* node ) {
1764 TIXMLASSERT( node );
1765 TIXMLASSERT(node->_document == this );
1766 if (node->_parent) {
1767 node->_parent->DeleteChild( node );
1768 }
1769 else {
1770 // Isn't in the tree.
1771 // Use the parent delete.
1772 // Also, we need to mark it tracked: we 'know'
1773 // it was never used.
1774 node->_memPool->SetTracked();
1775 // Call the static XMLNode version:
1776 XMLNode::DeleteNode(node);
1777 }
1778}
1779
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001780
Lee Thomason2fa81722012-11-09 12:37:46 -08001781XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001782{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001783 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001784 FILE* fp = callfopen( filename, "rb" );
1785 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 }
1789 LoadFile( fp );
1790 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001792}
1793
1794
Lee Thomason2fa81722012-11-09 12:37:46 -08001795XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001797 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001799 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001800 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001801 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1802 return _errorID;
1803 }
1804
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001806 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001808 if ( filelength == -1L ) {
1809 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1810 return _errorID;
1811 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001812
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001813 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001815 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001818
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 _charBuffer = new char[size+1];
1820 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 if ( read != size ) {
1822 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001825
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001827
Dmitry-Me97476b72015-01-01 16:15:57 +03001828 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001829 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001830}
1831
1832
Lee Thomason2fa81722012-11-09 12:37:46 -08001833XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834{
Dmitry-Me01578db2014-08-19 10:18:48 +04001835 FILE* fp = callfopen( filename, "w" );
1836 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 SaveFile(fp, compact);
1841 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001843}
1844
1845
Lee Thomason2fa81722012-11-09 12:37:46 -08001846XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001847{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 XMLPrinter stream( fp, compact );
1849 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001851}
1852
Lee Thomason1ff38e02012-02-14 18:18:16 -08001853
Lee Thomason2fa81722012-11-09 12:37:46 -08001854XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001855{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001856 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001857
Lee Thomason82d32002014-02-21 22:47:18 -08001858 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 }
1862 if ( len == (size_t)(-1) ) {
1863 len = strlen( p );
1864 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 _charBuffer = new char[ len+1 ];
1866 memcpy( _charBuffer, p, len );
1867 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001868
Dmitry-Me97476b72015-01-01 16:15:57 +03001869 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001870 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001871 // clean up now essentially dangling memory.
1872 // and the parse fail can put objects in the
1873 // pools that are dead and inaccessible.
1874 DeleteChildren();
1875 _elementPool.Clear();
1876 _attributePool.Clear();
1877 _textPool.Clear();
1878 _commentPool.Clear();
1879 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001881}
1882
1883
PKEuS1c5f99e2013-07-06 11:28:39 +02001884void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001885{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 XMLPrinter stdStreamer( stdout );
1887 if ( !streamer ) {
1888 streamer = &stdStreamer;
1889 }
1890 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001891}
1892
1893
Lee Thomason2fa81722012-11-09 12:37:46 -08001894void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001895{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001896 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 _errorID = error;
1898 _errorStr1 = str1;
1899 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001900}
1901
Lee Thomason331596e2014-09-11 14:56:43 -07001902const char* XMLDocument::ErrorName() const
1903{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001904 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001905 return _errorNames[_errorID];
1906}
Lee Thomason5cae8972012-01-24 18:03:07 -08001907
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001908void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001909{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001910 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 static const int LEN = 20;
1912 char buf1[LEN] = { 0 };
1913 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001914
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 if ( _errorStr1 ) {
1916 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 if ( _errorStr2 ) {
1919 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001921
Lee Thomason331596e2014-09-11 14:56:43 -07001922 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1923 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001925}
1926
Dmitry-Me97476b72015-01-01 16:15:57 +03001927void XMLDocument::Parse()
1928{
1929 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1930 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001931 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001932 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001933 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001934 if ( !*p ) {
1935 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1936 return;
1937 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001938 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001939}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001940
PKEuS1bfb9542013-08-04 13:51:17 +02001941XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 _elementJustOpened( false ),
1943 _firstElement( true ),
1944 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001945 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 _textDepth( -1 ),
1947 _processEntities( true ),
1948 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 _entityFlag[i] = false;
1952 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 }
1954 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001955 const char entityValue = entities[i].value;
1956 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1957 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001959 _restrictedEntityFlag[(unsigned char)'&'] = true;
1960 _restrictedEntityFlag[(unsigned char)'<'] = true;
1961 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001963}
1964
1965
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001966void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001967{
1968 va_list va;
1969 va_start( va, format );
1970
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 if ( _fp ) {
1972 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 }
1974 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001975#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001976 #if defined(WINCE)
1977 int len = 512;
1978 do {
1979 len = len*2;
1980 char* str = new char[len]();
1981 len = _vsnprintf(str, len, format, va);
1982 delete[] str;
1983 }while (len < 0);
1984 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001985 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001986 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987#else
1988 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001989#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 // Close out and re-start the va-args
1991 va_end( va );
1992 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001993 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1994#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001995 #if defined(WINCE)
1996 _vsnprintf( p, len+1, format, va );
1997 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001998 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001999 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002000#else
2001 vsnprintf( p, len+1, format, va );
2002#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002004 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002005}
2006
2007
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002008void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 for( int i=0; i<depth; ++i ) {
2011 Print( " " );
2012 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 // Look for runs of bytes between entities to print.
2019 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002021
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 while ( *q ) {
2024 // Remember, char is sometimes signed. (How many times has that bitten me?)
2025 if ( *q > 0 && *q < ENTITY_RANGE ) {
2026 // Check for entities. If one is found, flush
2027 // the stream up until the entity, write the
2028 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002029 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 while ( p < q ) {
2031 Print( "%c", *p );
2032 ++p;
2033 }
2034 for( int i=0; i<NUM_ENTITIES; ++i ) {
2035 if ( entities[i].value == *q ) {
2036 Print( "&%s;", entities[i].pattern );
2037 break;
2038 }
2039 }
2040 ++p;
2041 }
2042 }
2043 ++q;
2044 }
2045 }
2046 // Flush the remaining string. This will be the entire
2047 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 Print( "%s", p );
2050 }
Lee Thomason857b8682012-01-25 17:50:25 -08002051}
2052
U-Stream\Leeae25a442012-02-17 17:48:16 -08002053
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002054void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002057 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 -07002058 Print( "%s", bom );
2059 }
2060 if ( writeDec ) {
2061 PushDeclaration( "xml version=\"1.0\"" );
2062 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002063}
2064
2065
Uli Kusterer593a33d2014-02-01 12:48:51 +01002066void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002067{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002068 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002070
Uli Kusterer593a33d2014-02-01 12:48:51 +01002071 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002073 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002074 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002077
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 _elementJustOpened = true;
2080 _firstElement = false;
2081 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002082}
2083
2084
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002085void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002086{
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 Print( " %s=\"", name );
2089 PrintString( value, false );
2090 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002091}
2092
2093
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002094void XMLPrinter::PushAttribute( const char* name, int v )
2095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 char buf[BUF_SIZE];
2097 XMLUtil::ToStr( v, buf, BUF_SIZE );
2098 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002099}
2100
2101
2102void XMLPrinter::PushAttribute( const char* name, unsigned v )
2103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 char buf[BUF_SIZE];
2105 XMLUtil::ToStr( v, buf, BUF_SIZE );
2106 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
2109
2110void XMLPrinter::PushAttribute( const char* name, bool v )
2111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 char buf[BUF_SIZE];
2113 XMLUtil::ToStr( v, buf, BUF_SIZE );
2114 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
2117
2118void XMLPrinter::PushAttribute( const char* name, double v )
2119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 char buf[BUF_SIZE];
2121 XMLUtil::ToStr( v, buf, BUF_SIZE );
2122 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002123}
2124
2125
Uli Kustererca412e82014-02-01 13:35:05 +01002126void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002127{
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 --_depth;
2129 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002130
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 Print( "/>" );
2133 }
2134 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002135 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 }
2139 Print( "</%s>", name );
2140 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002141
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 if ( _textDepth == _depth ) {
2143 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
Uli Kustererca412e82014-02-01 13:35:05 +01002145 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( "\n" );
2147 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002149}
2150
2151
Dmitry-Mea092bc12014-12-23 17:57:05 +03002152void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002153{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002154 if ( !_elementJustOpened ) {
2155 return;
2156 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002159}
2160
2161
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002162void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002163{
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002165
Dmitry-Mea092bc12014-12-23 17:57:05 +03002166 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 if ( cdata ) {
2168 Print( "<![CDATA[" );
2169 Print( "%s", text );
2170 Print( "]]>" );
2171 }
2172 else {
2173 PrintString( text, true );
2174 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002175}
2176
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002177void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 char buf[BUF_SIZE];
2180 XMLUtil::ToStr( value, buf, BUF_SIZE );
2181 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002182}
2183
2184
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002185void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 char buf[BUF_SIZE];
2188 XMLUtil::ToStr( value, buf, BUF_SIZE );
2189 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002190}
2191
2192
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002193void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 char buf[BUF_SIZE];
2196 XMLUtil::ToStr( value, buf, BUF_SIZE );
2197 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002198}
2199
2200
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002201void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 char buf[BUF_SIZE];
2204 XMLUtil::ToStr( value, buf, BUF_SIZE );
2205 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002206}
2207
2208
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002209void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 char buf[BUF_SIZE];
2212 XMLUtil::ToStr( value, buf, BUF_SIZE );
2213 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002214}
2215
Lee Thomason5cae8972012-01-24 18:03:07 -08002216
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002217void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002218{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002219 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002226}
Lee Thomason751da522012-02-10 08:50:51 -08002227
2228
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002229void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002231 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238}
2239
2240
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002241void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002243 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002250}
2251
2252
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002253bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002254{
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 if ( doc.HasBOM() ) {
2257 PushHeader( true, false );
2258 }
2259 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002260}
2261
2262
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002263bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002264{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002265 const XMLElement* parentElem = element.Parent()->ToElement();
2266 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2267 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 while ( attribute ) {
2269 PushAttribute( attribute->Name(), attribute->Value() );
2270 attribute = attribute->Next();
2271 }
2272 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002273}
2274
2275
Uli Kustererca412e82014-02-01 13:35:05 +01002276bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002277{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002278 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002280}
2281
2282
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002283bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 PushText( text.Value(), text.CData() );
2286 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002287}
2288
2289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 PushComment( comment.Value() );
2293 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002294}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 PushDeclaration( declaration.Value() );
2299 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002300}
2301
2302
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002303bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 PushUnknown( unknown.Value() );
2306 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002307}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002308
Lee Thomason685b8952012-11-12 13:00:06 -08002309} // namespace tinyxml2
2310