blob: b8555c316af7960c5ae0229f9318a365cdbedef5 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
354 ptrdiff_t delta = 0;
355 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 if ( *(p+2) == 'x' ) {
358 // Hexadecimal.
359 if ( !*(p+3) ) {
360 return 0;
361 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 const char* q = p+3;
364 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 if ( !q || !*q ) {
367 return 0;
368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 delta = q-p;
371 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 while ( *q != 'x' ) {
374 if ( *q >= '0' && *q <= '9' ) {
375 ucs += mult * (*q - '0');
376 }
377 else if ( *q >= 'a' && *q <= 'f' ) {
378 ucs += mult * (*q - 'a' + 10);
379 }
380 else if ( *q >= 'A' && *q <= 'F' ) {
381 ucs += mult * (*q - 'A' + 10 );
382 }
383 else {
384 return 0;
385 }
386 mult *= 16;
387 --q;
388 }
389 }
390 else {
391 // Decimal.
392 if ( !*(p+2) ) {
393 return 0;
394 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 const char* q = p+2;
397 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800398
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 if ( !q || !*q ) {
400 return 0;
401 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 delta = q-p;
404 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 while ( *q != '#' ) {
407 if ( *q >= '0' && *q <= '9' ) {
408 ucs += mult * (*q - '0');
409 }
410 else {
411 return 0;
412 }
413 mult *= 10;
414 --q;
415 }
416 }
417 // convert the UCS to UTF-8
418 ConvertUTF32ToUTF8( ucs, value, length );
419 return p + delta + 1;
420 }
421 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800422}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800423
424
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700425void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442/*
443 ToStr() of a number is a very tricky topic.
444 https://github.com/leethomason/tinyxml2/issues/106
445*/
Lee Thomason21be8822012-07-15 17:27:22 -0700446void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458bool XMLUtil::ToInt( const char* str, int* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
461 return true;
462 }
463 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700464}
465
466bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474bool XMLUtil::ToBool( const char* str, bool* value )
475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700476 int ival = 0;
477 if ( ToInt( str, &ival )) {
478 *value = (ival==0) ? false : true;
479 return true;
480 }
481 if ( StringEqual( str, "true" ) ) {
482 *value = true;
483 return true;
484 }
485 else if ( StringEqual( str, "false" ) ) {
486 *value = false;
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
493bool XMLUtil::ToFloat( const char* str, float* value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToDouble( const char* str, double* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
504 return true;
505 }
506 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700507}
508
509
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700510char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400512 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300514 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return p;
516 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800519 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const char* xmlHeader = { "<?" };
521 static const char* commentHeader = { "<!--" };
522 static const char* dtdHeader = { "<!" };
523 static const char* cdataHeader = { "<![CDATA[" };
524 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 static const int xmlHeaderLen = 2;
527 static const int commentHeaderLen = 4;
528 static const int dtdHeaderLen = 2;
529 static const int cdataHeaderLen = 9;
530 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800531
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
533 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400534 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300536 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300542 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLComment( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += commentHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300548 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += cdataHeaderLen;
553 text->SetCData( true );
554 }
555 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300556 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300562 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700563 returnNode = new (_elementPool.Alloc()) XMLElement( this );
564 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 p += elementHeaderLen;
566 }
567 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_textPool.Alloc()) XMLText( this );
570 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p = start; // Back it up, all the text counts.
572 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 *node = returnNode;
575 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576}
577
578
Lee Thomason751da522012-02-10 08:50:51 -0800579bool XMLDocument::Accept( XMLVisitor* visitor ) const
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( visitor->VisitEnter( *this ) ) {
582 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
583 if ( !node->Accept( visitor ) ) {
584 break;
585 }
586 }
587 }
588 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800589}
Lee Thomason56bdd022012-02-09 18:16:58 -0800590
591
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592// --------- XMLNode ----------- //
593
594XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _document( doc ),
596 _parent( 0 ),
597 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200598 _prev( 0 ), _next( 0 ),
599 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800600{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601}
602
603
604XMLNode::~XMLNode()
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 if ( _parent ) {
608 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610}
611
Michael Daumling21626882013-10-22 17:03:37 +0200612const char* XMLNode::Value() const
613{
614 return _value.GetStr();
615}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800616
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800617void XMLNode::SetValue( const char* str, bool staticMem )
618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
622 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800625}
626
627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800628void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800629{
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300631 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700634
Dmitry-Mee3225b12014-09-03 11:03:11 +0400635 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800638}
639
640
641void XMLNode::Unlink( XMLNode* child )
642{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300643 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400667 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800668}
669
670
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
672{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300673 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300674 if ( addThis->_document != _document ) {
675 TIXMLASSERT( false );
676 return 0;
677 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800678 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700679
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 if ( _lastChild ) {
681 TIXMLASSERT( _firstChild );
682 TIXMLASSERT( _lastChild->_next == 0 );
683 _lastChild->_next = addThis;
684 addThis->_prev = _lastChild;
685 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
689 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( _firstChild == 0 );
691 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_prev = 0;
694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698}
699
700
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
702{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300703 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300704 if ( addThis->_document != _document ) {
705 TIXMLASSERT( false );
706 return 0;
707 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800708 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 if ( _firstChild ) {
711 TIXMLASSERT( _lastChild );
712 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 _firstChild->_prev = addThis;
715 addThis->_next = _firstChild;
716 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 }
720 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 TIXMLASSERT( _lastChild == 0 );
722 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 addThis->_prev = 0;
725 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400728 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729}
730
731
732XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
733{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300734 TIXMLASSERT( addThis );
735 if ( addThis->_document != _document ) {
736 TIXMLASSERT( false );
737 return 0;
738 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700739
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700741
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300743 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700744 return 0;
745 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 // The last node or the only node.
749 return InsertEndChild( addThis );
750 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800751 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 addThis->_prev = afterThis;
753 addThis->_next = afterThis->_next;
754 afterThis->_next->_prev = addThis;
755 afterThis->_next = addThis;
756 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800758}
759
760
761
762
Lee Thomason56bdd022012-02-09 18:16:58 -0800763const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 XMLElement* element = node->ToElement();
767 if ( element ) {
768 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
769 return element;
770 }
771 }
772 }
773 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800774}
775
776
Lee Thomason56bdd022012-02-09 18:16:58 -0800777const XMLElement* XMLNode::LastChildElement( const char* value ) const
778{
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 XMLElement* element = node->ToElement();
781 if ( element ) {
782 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
783 return element;
784 }
785 }
786 }
787 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800788}
789
790
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800791const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
792{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400793 for( XMLNode* node=this->_next; node; node = node->_next ) {
794 const XMLElement* element = node->ToElement();
795 if ( element
796 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
797 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
799 }
800 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800801}
802
803
804const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
805{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400806 for( XMLNode* node=_prev; node; node = node->_prev ) {
807 const XMLElement* element = node->ToElement();
808 if ( element
809 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
810 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
812 }
813 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800814}
815
816
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800817char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800818{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 // This is a recursive method, but thinking about it "at the current level"
820 // it is a pretty simple flat list:
821 // <foo/>
822 // <!-- comment -->
823 //
824 // With a special case:
825 // <foo>
826 // </foo>
827 // <!-- comment -->
828 //
829 // Where the closing element (/foo) *must* be the next thing after the opening
830 // element, and the names must match. BUT the tricky bit is that the closing
831 // element will be read by the child.
832 //
833 // 'endTag' is the end tag for this node, it is returned by a call to a child.
834 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 while( p && *p ) {
837 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800838
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 if ( p == 0 || node == 0 ) {
841 break;
842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 StrPair endTag;
845 p = node->ParseDeep( p, &endTag );
846 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400847 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 if ( !_document->Error() ) {
849 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 }
851 break;
852 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400854 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500856 // We read the end tag. Return it to the parent.
857 if ( ele->ClosingType() == XMLElement::CLOSING ) {
858 if ( parentEnd ) {
859 ele->_value.TransferTo( parentEnd );
860 }
861 node->_memPool->SetTracked(); // created and then immediately deleted.
862 DeleteNode( node );
863 return p;
864 }
865
866 // Handle an end tag returned to this level.
867 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400868 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400870 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 }
872 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400873 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 }
875 else if ( !endTag.Empty() ) {
876 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400877 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 }
879 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 if ( mismatch ) {
881 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500882 DeleteNode( node );
883 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400884 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
JayXondbfdd8f2014-12-12 20:07:14 -0500886 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800889}
890
Dmitry-Mee3225b12014-09-03 11:03:11 +0400891void XMLNode::DeleteNode( XMLNode* node )
892{
893 if ( node == 0 ) {
894 return;
895 }
896 MemPool* pool = node->_memPool;
897 node->~XMLNode();
898 pool->Free( node );
899}
900
Lee Thomason3cebdc42015-01-05 17:16:28 -0800901void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300902{
903 TIXMLASSERT( insertThis );
904 TIXMLASSERT( insertThis->_document == _document );
905
906 if ( insertThis->_parent )
907 insertThis->_parent->Unlink( insertThis );
908 else
909 insertThis->_memPool->SetTracked();
910}
911
Lee Thomason5492a1c2012-01-23 15:32:10 -0800912// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 const char* start = p;
916 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 return p;
922 }
923 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
925 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 flags |= StrPair::COLLAPSE_WHITESPACE;
927 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700928
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 if ( p && *p ) {
931 return p-1;
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300932 } else if ( !p ) {
933 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 }
935 }
936 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800937}
938
939
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
946 text->SetCData( this->CData() );
947 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
951bool XMLText::ShallowEqual( const XMLNode* compare ) const
952{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400953 const XMLText* text = compare->ToText();
954 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
Lee Thomason56bdd022012-02-09 18:16:58 -0800958bool XMLText::Accept( XMLVisitor* visitor ) const
959{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300960 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800962}
963
964
Lee Thomason3f57d272012-01-11 15:30:03 -0800965// --------- XMLComment ---------- //
966
Lee Thomasone4422302012-01-20 17:59:50 -0800967XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800968{
969}
970
971
Lee Thomasonce0763e2012-01-11 15:43:54 -0800972XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800973{
Lee Thomason3f57d272012-01-11 15:30:03 -0800974}
975
976
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800977char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 // Comment parses as text.
980 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800986}
987
988
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
990{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
995 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996}
997
998
999bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1000{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001001 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001002 const XMLComment* comment = compare->ToComment();
1003 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
Lee Thomason751da522012-02-10 08:50:51 -08001007bool XMLComment::Accept( XMLVisitor* visitor ) const
1008{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001009 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001011}
Lee Thomason56bdd022012-02-09 18:16:58 -08001012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014// --------- XMLDeclaration ---------- //
1015
1016XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1017{
1018}
1019
1020
1021XMLDeclaration::~XMLDeclaration()
1022{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001024}
1025
1026
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001027char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 // Declaration parses as text.
1030 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001036}
1037
1038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001039XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1045 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046}
1047
1048
1049bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1050{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001051 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001052 const XMLDeclaration* declaration = compare->ToDeclaration();
1053 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054}
1055
1056
1057
Lee Thomason50f97b22012-02-11 16:33:40 -08001058bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1059{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001060 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001062}
1063
1064// --------- XMLUnknown ---------- //
1065
1066XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1067{
1068}
1069
1070
1071XMLUnknown::~XMLUnknown()
1072{
1073}
1074
1075
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001076char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 // Unknown parses as text.
1079 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001080
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001086}
1087
1088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001089XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001092 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 }
1094 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1095 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001101 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001102 const XMLUnknown* unknown = compare->ToUnknown();
1103 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001104}
1105
1106
Lee Thomason50f97b22012-02-11 16:33:40 -08001107bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1108{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001109 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001111}
1112
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001113// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001114
1115const char* XMLAttribute::Name() const
1116{
1117 return _name.GetStr();
1118}
1119
1120const char* XMLAttribute::Value() const
1121{
1122 return _value.GetStr();
1123}
1124
Lee Thomason6f381b72012-03-02 12:59:39 -08001125char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( !p || !*p ) {
1130 return 0;
1131 }
Lee Thomason22aead12012-01-23 13:29:35 -08001132
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Skip white space before =
1134 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001135 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 return 0;
1137 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 ++p; // move up to opening quote
1140 p = XMLUtil::SkipWhiteSpace( p );
1141 if ( *p != '\"' && *p != '\'' ) {
1142 return 0;
1143 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001144
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 char endTag[2] = { *p, 0 };
1146 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001147
Lee Thomason624d43f2012-10-12 10:58:48 -07001148 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001150}
1151
1152
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001153void XMLAttribute::SetName( const char* n )
1154{
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001156}
1157
1158
Lee Thomason2fa81722012-11-09 12:37:46 -08001159XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( XMLUtil::ToInt( Value(), value )) {
1162 return XML_NO_ERROR;
1163 }
1164 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165}
1166
1167
Lee Thomason2fa81722012-11-09 12:37:46 -08001168XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 if ( XMLUtil::ToUnsigned( Value(), value )) {
1171 return XML_NO_ERROR;
1172 }
1173 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174}
1175
1176
Lee Thomason2fa81722012-11-09 12:37:46 -08001177XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( XMLUtil::ToBool( Value(), value )) {
1180 return XML_NO_ERROR;
1181 }
1182 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001183}
1184
1185
Lee Thomason2fa81722012-11-09 12:37:46 -08001186XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( XMLUtil::ToFloat( Value(), value )) {
1189 return XML_NO_ERROR;
1190 }
1191 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001192}
1193
1194
Lee Thomason2fa81722012-11-09 12:37:46 -08001195XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::ToDouble( Value(), value )) {
1198 return XML_NO_ERROR;
1199 }
1200 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201}
1202
1203
1204void XMLAttribute::SetAttribute( const char* v )
1205{
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210void XMLAttribute::SetAttribute( int v )
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 char buf[BUF_SIZE];
1213 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001216
1217
1218void XMLAttribute::SetAttribute( unsigned v )
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 char buf[BUF_SIZE];
1221 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223}
1224
1225
1226void XMLAttribute::SetAttribute( bool v )
1227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 char buf[BUF_SIZE];
1229 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001231}
1232
1233void XMLAttribute::SetAttribute( double v )
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 char buf[BUF_SIZE];
1236 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001237 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240void XMLAttribute::SetAttribute( float v )
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 char buf[BUF_SIZE];
1243 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001244 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001245}
1246
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001247
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001248// --------- XMLElement ---------- //
1249XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _closingType( 0 ),
1251 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001252{
1253}
1254
1255
1256XMLElement::~XMLElement()
1257{
Lee Thomason624d43f2012-10-12 10:58:48 -07001258 while( _rootAttribute ) {
1259 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001260 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001263}
1264
1265
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001266const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1267{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001268 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1270 return a;
1271 }
1272 }
1273 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001274}
1275
1276
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001277const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 const XMLAttribute* a = FindAttribute( name );
1280 if ( !a ) {
1281 return 0;
1282 }
1283 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1284 return a->Value();
1285 }
1286 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001287}
1288
1289
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001290const char* XMLElement::GetText() const
1291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001293 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 }
1295 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296}
1297
1298
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001299void XMLElement::SetText( const char* inText )
1300{
Uli Kusterer869bb592014-01-21 01:36:16 +01001301 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001302 FirstChild()->SetValue( inText );
1303 else {
1304 XMLText* theText = GetDocument()->NewText( inText );
1305 InsertFirstChild( theText );
1306 }
1307}
1308
Lee Thomason5bb2d802014-01-24 10:42:57 -08001309
1310void XMLElement::SetText( int v )
1311{
1312 char buf[BUF_SIZE];
1313 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314 SetText( buf );
1315}
1316
1317
1318void XMLElement::SetText( unsigned v )
1319{
1320 char buf[BUF_SIZE];
1321 XMLUtil::ToStr( v, buf, BUF_SIZE );
1322 SetText( buf );
1323}
1324
1325
1326void XMLElement::SetText( bool v )
1327{
1328 char buf[BUF_SIZE];
1329 XMLUtil::ToStr( v, buf, BUF_SIZE );
1330 SetText( buf );
1331}
1332
1333
1334void XMLElement::SetText( float v )
1335{
1336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
1338 SetText( buf );
1339}
1340
1341
1342void XMLElement::SetText( double v )
1343{
1344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
1346 SetText( buf );
1347}
1348
1349
MortenMacFly4ee49f12013-01-14 20:03:14 +01001350XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001353 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 return XML_SUCCESS;
1356 }
1357 return XML_CAN_NOT_CONVERT_TEXT;
1358 }
1359 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001360}
1361
1362
MortenMacFly4ee49f12013-01-14 20:03:14 +01001363XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001366 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 return XML_SUCCESS;
1369 }
1370 return XML_CAN_NOT_CONVERT_TEXT;
1371 }
1372 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001373}
1374
1375
MortenMacFly4ee49f12013-01-14 20:03:14 +01001376XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001379 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 return XML_SUCCESS;
1382 }
1383 return XML_CAN_NOT_CONVERT_TEXT;
1384 }
1385 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001386}
1387
1388
MortenMacFly4ee49f12013-01-14 20:03:14 +01001389XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001392 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return XML_SUCCESS;
1395 }
1396 return XML_CAN_NOT_CONVERT_TEXT;
1397 }
1398 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001399}
1400
1401
MortenMacFly4ee49f12013-01-14 20:03:14 +01001402XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001405 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return XML_SUCCESS;
1408 }
1409 return XML_CAN_NOT_CONVERT_TEXT;
1410 }
1411 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001412}
1413
1414
1415
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 XMLAttribute* last = 0;
1419 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1424 break;
1425 }
1426 }
1427 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001428 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1430 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
1434 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001438 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441}
1442
1443
U-Stream\Leeae25a442012-02-17 17:48:16 -08001444void XMLElement::DeleteAttribute( const char* name )
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1449 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 }
1452 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001455 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 break;
1457 }
1458 prev = a;
1459 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001460}
1461
1462
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001463char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 const char* start = p;
1466 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 // Read the attributes.
1469 while( p ) {
1470 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001471 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 return 0;
1474 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001477 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001478 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1480 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001481 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001482
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001485 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 return 0;
1488 }
1489 // There is a minor bug here: if the attribute in the source xml
1490 // document is duplicated, it will not be detected and the
1491 // attribute will be doubly added. However, tracking the 'prevAttribute'
1492 // avoids re-scanning the attribute list. Preferring performance for
1493 // now, may reconsider in the future.
1494 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 }
1500 prevAttribute = attrib;
1501 }
1502 // end of the tag
1503 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 return p+2; // done; sealed element.
1506 }
1507 // end of the tag
1508 else if ( *p == '>' ) {
1509 ++p;
1510 break;
1511 }
1512 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
1516 }
1517 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001518}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001519
Dmitry-Mee3225b12014-09-03 11:03:11 +04001520void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1521{
1522 if ( attribute == 0 ) {
1523 return;
1524 }
1525 MemPool* pool = attribute->_memPool;
1526 attribute->~XMLAttribute();
1527 pool->Free( attribute );
1528}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Lee Thomason67d61312012-01-24 16:01:51 -08001530//
1531// <ele></ele>
1532// <ele>foo<b>bar</b></ele>
1533//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001534char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 // Read the element name.
1537 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001538
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 // The closing element is the </element> form. It is
1540 // parsed just like a regular element then deleted from
1541 // the DOM.
1542 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001543 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 ++p;
1545 }
Lee Thomason67d61312012-01-24 16:01:51 -08001546
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 p = _value.ParseName( p );
1548 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 return 0;
1550 }
Lee Thomason67d61312012-01-24 16:01:51 -08001551
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 return p;
1555 }
Lee Thomason67d61312012-01-24 16:01:51 -08001556
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 p = XMLNode::ParseDeep( p, strPair );
1558 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001559}
1560
1561
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001562
1563XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001566 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 }
1568 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1569 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1570 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1571 }
1572 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001573}
1574
1575
1576bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1577{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001578 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 const XMLElement* other = compare->ToElement();
1580 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001581
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 const XMLAttribute* a=FirstAttribute();
1583 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001584
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 while ( a && b ) {
1586 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1587 return false;
1588 }
1589 a = a->Next();
1590 b = b->Next();
1591 }
1592 if ( a || b ) {
1593 // different count
1594 return false;
1595 }
1596 return true;
1597 }
1598 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001599}
1600
1601
Lee Thomason751da522012-02-10 08:50:51 -08001602bool XMLElement::Accept( XMLVisitor* visitor ) const
1603{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001604 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1607 if ( !node->Accept( visitor ) ) {
1608 break;
1609 }
1610 }
1611 }
1612 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001613}
Lee Thomason56bdd022012-02-09 18:16:58 -08001614
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001615
Lee Thomason3f57d272012-01-11 15:30:03 -08001616// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001617
1618// Warning: List must match 'enum XMLError'
1619const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1620 "XML_SUCCESS",
1621 "XML_NO_ATTRIBUTE",
1622 "XML_WRONG_ATTRIBUTE_TYPE",
1623 "XML_ERROR_FILE_NOT_FOUND",
1624 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1625 "XML_ERROR_FILE_READ_ERROR",
1626 "XML_ERROR_ELEMENT_MISMATCH",
1627 "XML_ERROR_PARSING_ELEMENT",
1628 "XML_ERROR_PARSING_ATTRIBUTE",
1629 "XML_ERROR_IDENTIFYING_TAG",
1630 "XML_ERROR_PARSING_TEXT",
1631 "XML_ERROR_PARSING_CDATA",
1632 "XML_ERROR_PARSING_COMMENT",
1633 "XML_ERROR_PARSING_DECLARATION",
1634 "XML_ERROR_PARSING_UNKNOWN",
1635 "XML_ERROR_EMPTY_DOCUMENT",
1636 "XML_ERROR_MISMATCHED_ELEMENT",
1637 "XML_ERROR_PARSING",
1638 "XML_CAN_NOT_CONVERT_TEXT",
1639 "XML_NO_TEXT_NODE"
1640};
1641
1642
Lee Thomason624d43f2012-10-12 10:58:48 -07001643XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 _writeBOM( false ),
1646 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001647 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 _whitespace( whitespace ),
1649 _errorStr1( 0 ),
1650 _errorStr2( 0 ),
1651 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001652{
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001654}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001655
1656
Lee Thomason3f57d272012-01-11 15:30:03 -08001657XMLDocument::~XMLDocument()
1658{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001659 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001660}
1661
1662
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001663void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001664{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001665 DeleteChildren();
1666
Dmitry-Meab37df82014-11-28 12:08:36 +03001667#ifdef DEBUG
1668 const bool hadError = Error();
1669#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _errorID = XML_NO_ERROR;
1671 _errorStr1 = 0;
1672 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001673
Lee Thomason624d43f2012-10-12 10:58:48 -07001674 delete [] _charBuffer;
1675 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001676
1677#if 0
1678 _textPool.Trace( "text" );
1679 _elementPool.Trace( "element" );
1680 _commentPool.Trace( "comment" );
1681 _attributePool.Trace( "attribute" );
1682#endif
1683
1684#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001685 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001686 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1687 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1688 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1689 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1690 }
1691#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001692}
1693
Lee Thomason3f57d272012-01-11 15:30:03 -08001694
Lee Thomason2c85a712012-01-31 08:24:24 -08001695XMLElement* XMLDocument::NewElement( const char* name )
1696{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001697 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1699 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 ele->SetName( name );
1701 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001702}
1703
1704
Lee Thomason1ff38e02012-02-14 18:18:16 -08001705XMLComment* XMLDocument::NewComment( const char* str )
1706{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001707 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1709 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 comment->SetValue( str );
1711 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001712}
1713
1714
1715XMLText* XMLDocument::NewText( const char* str )
1716{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001717 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1719 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 text->SetValue( str );
1721 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001722}
1723
1724
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001725XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1726{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001727 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1729 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1731 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001732}
1733
1734
1735XMLUnknown* XMLDocument::NewUnknown( const char* str )
1736{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001737 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1739 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 unk->SetValue( str );
1741 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001742}
1743
Dmitry-Me01578db2014-08-19 10:18:48 +04001744static FILE* callfopen( const char* filepath, const char* mode )
1745{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001746 TIXMLASSERT( filepath );
1747 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001748#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1749 FILE* fp = 0;
1750 errno_t err = fopen_s( &fp, filepath, mode );
1751 if ( err ) {
1752 return 0;
1753 }
1754#else
1755 FILE* fp = fopen( filepath, mode );
1756#endif
1757 return fp;
1758}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001759
1760void XMLDocument::DeleteNode( XMLNode* node ) {
1761 TIXMLASSERT( node );
1762 TIXMLASSERT(node->_document == this );
1763 if (node->_parent) {
1764 node->_parent->DeleteChild( node );
1765 }
1766 else {
1767 // Isn't in the tree.
1768 // Use the parent delete.
1769 // Also, we need to mark it tracked: we 'know'
1770 // it was never used.
1771 node->_memPool->SetTracked();
1772 // Call the static XMLNode version:
1773 XMLNode::DeleteNode(node);
1774 }
1775}
1776
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001777
Lee Thomason2fa81722012-11-09 12:37:46 -08001778XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001779{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001780 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001781 FILE* fp = callfopen( filename, "rb" );
1782 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
1786 LoadFile( fp );
1787 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001789}
1790
1791
Lee Thomason2fa81722012-11-09 12:37:46 -08001792XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001793{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001794 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001796 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001797 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001798 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1799 return _errorID;
1800 }
1801
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001803 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001805 if ( filelength == -1L ) {
1806 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1807 return _errorID;
1808 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001809
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001810 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001812 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001813 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001815
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 _charBuffer = new char[size+1];
1817 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 if ( read != size ) {
1819 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001822
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001824
Dmitry-Me97476b72015-01-01 16:15:57 +03001825 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001827}
1828
1829
Lee Thomason2fa81722012-11-09 12:37:46 -08001830XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001831{
Dmitry-Me01578db2014-08-19 10:18:48 +04001832 FILE* fp = callfopen( filename, "w" );
1833 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
1837 SaveFile(fp, compact);
1838 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001840}
1841
1842
Lee Thomason2fa81722012-11-09 12:37:46 -08001843XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 XMLPrinter stream( fp, compact );
1846 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848}
1849
Lee Thomason1ff38e02012-02-14 18:18:16 -08001850
Lee Thomason2fa81722012-11-09 12:37:46 -08001851XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001852{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001853 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001854
Lee Thomason82d32002014-02-21 22:47:18 -08001855 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
1859 if ( len == (size_t)(-1) ) {
1860 len = strlen( p );
1861 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 _charBuffer = new char[ len+1 ];
1863 memcpy( _charBuffer, p, len );
1864 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001865
Dmitry-Me97476b72015-01-01 16:15:57 +03001866 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001867 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001868 // clean up now essentially dangling memory.
1869 // and the parse fail can put objects in the
1870 // pools that are dead and inaccessible.
1871 DeleteChildren();
1872 _elementPool.Clear();
1873 _attributePool.Clear();
1874 _textPool.Clear();
1875 _commentPool.Clear();
1876 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001877 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001878}
1879
1880
PKEuS1c5f99e2013-07-06 11:28:39 +02001881void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001882{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 XMLPrinter stdStreamer( stdout );
1884 if ( !streamer ) {
1885 streamer = &stdStreamer;
1886 }
1887 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001888}
1889
1890
Lee Thomason2fa81722012-11-09 12:37:46 -08001891void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001892{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001893 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 _errorID = error;
1895 _errorStr1 = str1;
1896 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001897}
1898
Lee Thomason331596e2014-09-11 14:56:43 -07001899const char* XMLDocument::ErrorName() const
1900{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001901 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001902 return _errorNames[_errorID];
1903}
Lee Thomason5cae8972012-01-24 18:03:07 -08001904
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001905void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001906{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001907 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 static const int LEN = 20;
1909 char buf1[LEN] = { 0 };
1910 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001911
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 if ( _errorStr1 ) {
1913 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 if ( _errorStr2 ) {
1916 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001918
Lee Thomason331596e2014-09-11 14:56:43 -07001919 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1920 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001922}
1923
Dmitry-Me97476b72015-01-01 16:15:57 +03001924void XMLDocument::Parse()
1925{
1926 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1927 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001928 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001929 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001930 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001931 if ( !*p ) {
1932 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1933 return;
1934 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001935 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001936}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001937
PKEuS1bfb9542013-08-04 13:51:17 +02001938XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 _elementJustOpened( false ),
1940 _firstElement( true ),
1941 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001942 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 _textDepth( -1 ),
1944 _processEntities( true ),
1945 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 _entityFlag[i] = false;
1949 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 }
1951 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001952 const char entityValue = entities[i].value;
1953 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1954 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001955 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001956 _restrictedEntityFlag[(unsigned char)'&'] = true;
1957 _restrictedEntityFlag[(unsigned char)'<'] = true;
1958 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001960}
1961
1962
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001963void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001964{
1965 va_list va;
1966 va_start( va, format );
1967
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 if ( _fp ) {
1969 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 }
1971 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001972#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001973 #if defined(WINCE)
1974 int len = 512;
1975 do {
1976 len = len*2;
1977 char* str = new char[len]();
1978 len = _vsnprintf(str, len, format, va);
1979 delete[] str;
1980 }while (len < 0);
1981 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001982 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001983 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001984#else
1985 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001986#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 // Close out and re-start the va-args
1988 va_end( va );
1989 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001990 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1991#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001992 #if defined(WINCE)
1993 _vsnprintf( p, len+1, format, va );
1994 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001995 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001996 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001997#else
1998 vsnprintf( p, len+1, format, va );
1999#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002001 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002002}
2003
2004
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002005void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002006{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 for( int i=0; i<depth; ++i ) {
2008 Print( " " );
2009 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002010}
2011
2012
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002013void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002014{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 // Look for runs of bytes between entities to print.
2016 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002018
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 while ( *q ) {
2021 // Remember, char is sometimes signed. (How many times has that bitten me?)
2022 if ( *q > 0 && *q < ENTITY_RANGE ) {
2023 // Check for entities. If one is found, flush
2024 // the stream up until the entity, write the
2025 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002026 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 while ( p < q ) {
2028 Print( "%c", *p );
2029 ++p;
2030 }
2031 for( int i=0; i<NUM_ENTITIES; ++i ) {
2032 if ( entities[i].value == *q ) {
2033 Print( "&%s;", entities[i].pattern );
2034 break;
2035 }
2036 }
2037 ++p;
2038 }
2039 }
2040 ++q;
2041 }
2042 }
2043 // Flush the remaining string. This will be the entire
2044 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 Print( "%s", p );
2047 }
Lee Thomason857b8682012-01-25 17:50:25 -08002048}
2049
U-Stream\Leeae25a442012-02-17 17:48:16 -08002050
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002051void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002052{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002054 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 -07002055 Print( "%s", bom );
2056 }
2057 if ( writeDec ) {
2058 PushDeclaration( "xml version=\"1.0\"" );
2059 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002060}
2061
2062
Uli Kusterer593a33d2014-02-01 12:48:51 +01002063void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002064{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002065 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002067
Uli Kusterer593a33d2014-02-01 12:48:51 +01002068 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002070 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002071 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002074
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 _elementJustOpened = true;
2077 _firstElement = false;
2078 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002079}
2080
2081
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002082void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002083{
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 Print( " %s=\"", name );
2086 PrintString( value, false );
2087 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002088}
2089
2090
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002091void XMLPrinter::PushAttribute( const char* name, int v )
2092{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 char buf[BUF_SIZE];
2094 XMLUtil::ToStr( v, buf, BUF_SIZE );
2095 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002096}
2097
2098
2099void XMLPrinter::PushAttribute( const char* name, unsigned v )
2100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 char buf[BUF_SIZE];
2102 XMLUtil::ToStr( v, buf, BUF_SIZE );
2103 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002104}
2105
2106
2107void XMLPrinter::PushAttribute( const char* name, bool v )
2108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 char buf[BUF_SIZE];
2110 XMLUtil::ToStr( v, buf, BUF_SIZE );
2111 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002112}
2113
2114
2115void XMLPrinter::PushAttribute( const char* name, double v )
2116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 char buf[BUF_SIZE];
2118 XMLUtil::ToStr( v, buf, BUF_SIZE );
2119 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002120}
2121
2122
Uli Kustererca412e82014-02-01 13:35:05 +01002123void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002124{
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 --_depth;
2126 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002127
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 Print( "/>" );
2130 }
2131 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002132 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 }
2136 Print( "</%s>", name );
2137 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002138
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 if ( _textDepth == _depth ) {
2140 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 }
Uli Kustererca412e82014-02-01 13:35:05 +01002142 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 Print( "\n" );
2144 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002146}
2147
2148
Dmitry-Mea092bc12014-12-23 17:57:05 +03002149void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002150{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002151 if ( !_elementJustOpened ) {
2152 return;
2153 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002156}
2157
2158
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002159void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002160{
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002162
Dmitry-Mea092bc12014-12-23 17:57:05 +03002163 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 if ( cdata ) {
2165 Print( "<![CDATA[" );
2166 Print( "%s", text );
2167 Print( "]]>" );
2168 }
2169 else {
2170 PrintString( text, true );
2171 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002172}
2173
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002174void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 char buf[BUF_SIZE];
2177 XMLUtil::ToStr( value, buf, BUF_SIZE );
2178 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002179}
2180
2181
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002182void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 char buf[BUF_SIZE];
2185 XMLUtil::ToStr( value, buf, BUF_SIZE );
2186 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002187}
2188
2189
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002190void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 char buf[BUF_SIZE];
2193 XMLUtil::ToStr( value, buf, BUF_SIZE );
2194 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002195}
2196
2197
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002198void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 char buf[BUF_SIZE];
2201 XMLUtil::ToStr( value, buf, BUF_SIZE );
2202 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002203}
2204
2205
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002206void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 char buf[BUF_SIZE];
2209 XMLUtil::ToStr( value, buf, BUF_SIZE );
2210 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002211}
2212
Lee Thomason5cae8972012-01-24 18:03:07 -08002213
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002214void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002215{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002216 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002223}
Lee Thomason751da522012-02-10 08:50:51 -08002224
2225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002228 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002235}
2236
2237
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002238void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002239{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002240 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002247}
2248
2249
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002250bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002251{
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 if ( doc.HasBOM() ) {
2254 PushHeader( true, false );
2255 }
2256 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002257}
2258
2259
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002260bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002261{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002262 const XMLElement* parentElem = element.Parent()->ToElement();
2263 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2264 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 while ( attribute ) {
2266 PushAttribute( attribute->Name(), attribute->Value() );
2267 attribute = attribute->Next();
2268 }
2269 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002270}
2271
2272
Uli Kustererca412e82014-02-01 13:35:05 +01002273bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002274{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002275 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002277}
2278
2279
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002280bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 PushText( text.Value(), text.CData() );
2283 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002284}
2285
2286
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002287bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 PushComment( comment.Value() );
2290 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002291}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002292
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002293bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 PushDeclaration( declaration.Value() );
2296 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297}
2298
2299
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002300bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 PushUnknown( unknown.Value() );
2303 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002305
Lee Thomason685b8952012-11-12 13:00:06 -08002306} // namespace tinyxml2
2307