blob: 99cca41b281897aa211902475f141929d4b136e2 [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;
Dmitry-Me9f56e122015-01-12 10:07:54 +0300356 const char semicolon = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 if ( *(p+2) == 'x' ) {
359 // Hexadecimal.
360 if ( !*(p+3) ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 const char* q = p+3;
Dmitry-Me9f56e122015-01-12 10:07:54 +0300365 q = strchr( q, semicolon );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Dmitry-Me9f56e122015-01-12 10:07:54 +0300367 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 return 0;
369 }
Dmitry-Me9f56e122015-01-12 10:07:54 +0300370 TIXMLASSERT( *q == semicolon );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800371
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 delta = q-p;
373 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700375 while ( *q != 'x' ) {
376 if ( *q >= '0' && *q <= '9' ) {
377 ucs += mult * (*q - '0');
378 }
379 else if ( *q >= 'a' && *q <= 'f' ) {
380 ucs += mult * (*q - 'a' + 10);
381 }
382 else if ( *q >= 'A' && *q <= 'F' ) {
383 ucs += mult * (*q - 'A' + 10 );
384 }
385 else {
386 return 0;
387 }
388 mult *= 16;
389 --q;
390 }
391 }
392 else {
393 // Decimal.
394 if ( !*(p+2) ) {
395 return 0;
396 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800397
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 const char* q = p+2;
Dmitry-Me9f56e122015-01-12 10:07:54 +0300399 q = strchr( q, semicolon );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Dmitry-Me9f56e122015-01-12 10:07:54 +0300401 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 return 0;
403 }
Dmitry-Me9f56e122015-01-12 10:07:54 +0300404 TIXMLASSERT( *q == semicolon );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 delta = q-p;
407 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 while ( *q != '#' ) {
410 if ( *q >= '0' && *q <= '9' ) {
411 ucs += mult * (*q - '0');
412 }
413 else {
414 return 0;
415 }
416 mult *= 10;
417 --q;
418 }
419 }
420 // convert the UCS to UTF-8
421 ConvertUTF32ToUTF8( ucs, value, length );
422 return p + delta + 1;
423 }
424 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800426
427
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700428void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
439
440void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800445/*
446 ToStr() of a number is a very tricky topic.
447 https://github.com/leethomason/tinyxml2/issues/106
448*/
Lee Thomason21be8822012-07-15 17:27:22 -0700449void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
450{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800451 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454
455void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
456{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800457 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460
461bool XMLUtil::ToInt( const char* str, int* value )
462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
464 return true;
465 }
466 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700467}
468
469bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
472 return true;
473 }
474 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700475}
476
477bool XMLUtil::ToBool( const char* str, bool* value )
478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 int ival = 0;
480 if ( ToInt( str, &ival )) {
481 *value = (ival==0) ? false : true;
482 return true;
483 }
484 if ( StringEqual( str, "true" ) ) {
485 *value = true;
486 return true;
487 }
488 else if ( StringEqual( str, "false" ) ) {
489 *value = false;
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495
496bool XMLUtil::ToFloat( const char* str, float* value )
497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700498 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
499 return true;
500 }
501 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700502}
503
504bool XMLUtil::ToDouble( const char* str, double* value )
505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
507 return true;
508 }
509 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700510}
511
512
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700513char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400515 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300517 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 return p;
519 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800520
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800522 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 static const char* xmlHeader = { "<?" };
524 static const char* commentHeader = { "<!--" };
525 static const char* dtdHeader = { "<!" };
526 static const char* cdataHeader = { "<![CDATA[" };
527 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 static const int xmlHeaderLen = 2;
530 static const int commentHeaderLen = 4;
531 static const int dtdHeaderLen = 2;
532 static const int cdataHeaderLen = 9;
533 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800534
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
536 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400537 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300539 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += xmlHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300545 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700546 returnNode = new (_commentPool.Alloc()) XMLComment( this );
547 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 p += commentHeaderLen;
549 }
550 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300551 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p += cdataHeaderLen;
556 text->SetCData( true );
557 }
558 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300559 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
561 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p += dtdHeaderLen;
563 }
564 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300565 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 returnNode = new (_elementPool.Alloc()) XMLElement( this );
567 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 p += elementHeaderLen;
569 }
570 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300571 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700572 returnNode = new (_textPool.Alloc()) XMLText( this );
573 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700574 p = start; // Back it up, all the text counts.
575 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 *node = returnNode;
578 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579}
580
581
Lee Thomason751da522012-02-10 08:50:51 -0800582bool XMLDocument::Accept( XMLVisitor* visitor ) const
583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 if ( visitor->VisitEnter( *this ) ) {
585 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
586 if ( !node->Accept( visitor ) ) {
587 break;
588 }
589 }
590 }
591 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800592}
Lee Thomason56bdd022012-02-09 18:16:58 -0800593
594
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595// --------- XMLNode ----------- //
596
597XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700598 _document( doc ),
599 _parent( 0 ),
600 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200601 _prev( 0 ), _next( 0 ),
602 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800603{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604}
605
606
607XMLNode::~XMLNode()
608{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700610 if ( _parent ) {
611 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700612 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613}
614
Michael Daumling21626882013-10-22 17:03:37 +0200615const char* XMLNode::Value() const
616{
617 return _value.GetStr();
618}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800619
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620void XMLNode::SetValue( const char* str, bool staticMem )
621{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 }
625 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700626 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800628}
629
630
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800631void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800632{
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300634 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700635 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700637
Dmitry-Mee3225b12014-09-03 11:03:11 +0400638 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800641}
642
643
644void XMLNode::Unlink( XMLNode* child )
645{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300646 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300647 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _firstChild ) {
649 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 if ( child == _lastChild ) {
652 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 }
Lee Thomasond923c672012-01-23 08:44:25 -0800654
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_prev ) {
656 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 if ( child->_next ) {
659 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700661 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800662}
663
664
U-Stream\Leeae25a442012-02-17 17:48:16 -0800665void XMLNode::DeleteChild( XMLNode* node )
666{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300667 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300668 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400670 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800671}
672
673
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
675{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300676 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300677 if ( addThis->_document != _document ) {
678 TIXMLASSERT( false );
679 return 0;
680 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800681 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 if ( _lastChild ) {
684 TIXMLASSERT( _firstChild );
685 TIXMLASSERT( _lastChild->_next == 0 );
686 _lastChild->_next = addThis;
687 addThis->_prev = _lastChild;
688 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
692 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 TIXMLASSERT( _firstChild == 0 );
694 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_prev = 0;
697 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701}
702
703
Lee Thomason1ff38e02012-02-14 18:18:16 -0800704XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
705{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300706 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300707 if ( addThis->_document != _document ) {
708 TIXMLASSERT( false );
709 return 0;
710 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800711 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 if ( _firstChild ) {
714 TIXMLASSERT( _lastChild );
715 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 _firstChild->_prev = addThis;
718 addThis->_next = _firstChild;
719 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 }
723 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 TIXMLASSERT( _lastChild == 0 );
725 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800726
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_prev = 0;
728 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400731 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800732}
733
734
735XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
736{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300737 TIXMLASSERT( addThis );
738 if ( addThis->_document != _document ) {
739 TIXMLASSERT( false );
740 return 0;
741 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700742
Dmitry-Meabb2d042014-12-09 12:59:31 +0300743 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700744
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300746 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 return 0;
748 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800749
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 // The last node or the only node.
752 return InsertEndChild( addThis );
753 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800754 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 addThis->_prev = afterThis;
756 addThis->_next = afterThis->_next;
757 afterThis->_next->_prev = addThis;
758 afterThis->_next = addThis;
759 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800761}
762
763
764
765
Lee Thomason56bdd022012-02-09 18:16:58 -0800766const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800767{
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 XMLElement* element = node->ToElement();
770 if ( element ) {
771 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
772 return element;
773 }
774 }
775 }
776 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800777}
778
779
Lee Thomason56bdd022012-02-09 18:16:58 -0800780const XMLElement* XMLNode::LastChildElement( const char* value ) const
781{
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 XMLElement* element = node->ToElement();
784 if ( element ) {
785 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
786 return element;
787 }
788 }
789 }
790 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800791}
792
793
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
795{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400796 for( XMLNode* node=this->_next; node; node = node->_next ) {
797 const XMLElement* element = node->ToElement();
798 if ( element
799 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
800 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 }
802 }
803 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800804}
805
806
807const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
808{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400809 for( XMLNode* node=_prev; node; node = node->_prev ) {
810 const XMLElement* element = node->ToElement();
811 if ( element
812 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
813 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
815 }
816 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800817}
818
819
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800820char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800821{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 // This is a recursive method, but thinking about it "at the current level"
823 // it is a pretty simple flat list:
824 // <foo/>
825 // <!-- comment -->
826 //
827 // With a special case:
828 // <foo>
829 // </foo>
830 // <!-- comment -->
831 //
832 // Where the closing element (/foo) *must* be the next thing after the opening
833 // element, and the names must match. BUT the tricky bit is that the closing
834 // element will be read by the child.
835 //
836 // 'endTag' is the end tag for this node, it is returned by a call to a child.
837 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800838
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 while( p && *p ) {
840 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800841
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 if ( p == 0 || node == 0 ) {
844 break;
845 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 StrPair endTag;
848 p = node->ParseDeep( p, &endTag );
849 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400850 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 if ( !_document->Error() ) {
852 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 break;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400857 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500859 // We read the end tag. Return it to the parent.
860 if ( ele->ClosingType() == XMLElement::CLOSING ) {
861 if ( parentEnd ) {
862 ele->_value.TransferTo( parentEnd );
863 }
864 node->_memPool->SetTracked(); // created and then immediately deleted.
865 DeleteNode( node );
866 return p;
867 }
868
869 // Handle an end tag returned to this level.
870 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400871 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300872 if ( endTag.Empty() ) {
873 if ( ele->ClosingType() == XMLElement::OPEN ) {
874 mismatch = true;
875 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300877 else {
878 if ( ele->ClosingType() != XMLElement::OPEN ) {
879 mismatch = true;
880 }
881 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400882 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400885 if ( mismatch ) {
886 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500887 DeleteNode( node );
888 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400889 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 }
JayXondbfdd8f2014-12-12 20:07:14 -0500891 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 }
893 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800894}
895
Dmitry-Mee3225b12014-09-03 11:03:11 +0400896void XMLNode::DeleteNode( XMLNode* node )
897{
898 if ( node == 0 ) {
899 return;
900 }
901 MemPool* pool = node->_memPool;
902 node->~XMLNode();
903 pool->Free( node );
904}
905
Lee Thomason3cebdc42015-01-05 17:16:28 -0800906void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300907{
908 TIXMLASSERT( insertThis );
909 TIXMLASSERT( insertThis->_document == _document );
910
911 if ( insertThis->_parent )
912 insertThis->_parent->Unlink( insertThis );
913 else
914 insertThis->_memPool->SetTracked();
915}
916
Lee Thomason5492a1c2012-01-23 15:32:10 -0800917// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800918char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 const char* start = p;
921 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 }
926 return p;
927 }
928 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
930 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 flags |= StrPair::COLLAPSE_WHITESPACE;
932 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 if ( p && *p ) {
936 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300937 }
938 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300939 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800943}
944
945
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700949 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 }
951 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
952 text->SetCData( this->CData() );
953 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954}
955
956
957bool XMLText::ShallowEqual( const XMLNode* compare ) const
958{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400959 const XMLText* text = compare->ToText();
960 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961}
962
963
Lee Thomason56bdd022012-02-09 18:16:58 -0800964bool XMLText::Accept( XMLVisitor* visitor ) const
965{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300966 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800968}
969
970
Lee Thomason3f57d272012-01-11 15:30:03 -0800971// --------- XMLComment ---------- //
972
Lee Thomasone4422302012-01-20 17:59:50 -0800973XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800974{
975}
976
977
Lee Thomasonce0763e2012-01-11 15:43:54 -0800978XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
Lee Thomason3f57d272012-01-11 15:30:03 -0800980}
981
982
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800983char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 // Comment parses as text.
986 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700987 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 }
991 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800992}
993
994
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1001 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
1005bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1006{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001007 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLComment* comment = compare->ToComment();
1009 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
Lee Thomason751da522012-02-10 08:50:51 -08001013bool XMLComment::Accept( XMLVisitor* visitor ) const
1014{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001015 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001017}
Lee Thomason56bdd022012-02-09 18:16:58 -08001018
1019
Lee Thomason50f97b22012-02-11 16:33:40 -08001020// --------- XMLDeclaration ---------- //
1021
1022XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1023{
1024}
1025
1026
1027XMLDeclaration::~XMLDeclaration()
1028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001030}
1031
1032
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 // Declaration parses as text.
1036 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001042}
1043
1044
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 }
1050 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1051 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1056{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001057 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001058 const XMLDeclaration* declaration = compare->ToDeclaration();
1059 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001060}
1061
1062
1063
Lee Thomason50f97b22012-02-11 16:33:40 -08001064bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1065{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001066 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
1070// --------- XMLUnknown ---------- //
1071
1072XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1073{
1074}
1075
1076
1077XMLUnknown::~XMLUnknown()
1078{
1079}
1080
1081
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001082char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Unknown parses as text.
1085 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001086
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001092}
1093
1094
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001098 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 }
1100 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1101 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
1105bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001108 const XMLUnknown* unknown = compare->ToUnknown();
1109 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110}
1111
1112
Lee Thomason50f97b22012-02-11 16:33:40 -08001113bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1114{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001115 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001117}
1118
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001119// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001120
1121const char* XMLAttribute::Name() const
1122{
1123 return _name.GetStr();
1124}
1125
1126const char* XMLAttribute::Value() const
1127{
1128 return _value.GetStr();
1129}
1130
Lee Thomason6f381b72012-03-02 12:59:39 -08001131char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001134 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !p || !*p ) {
1136 return 0;
1137 }
Lee Thomason22aead12012-01-23 13:29:35 -08001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 // Skip white space before =
1140 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001141 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 return 0;
1143 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001144
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 ++p; // move up to opening quote
1146 p = XMLUtil::SkipWhiteSpace( p );
1147 if ( *p != '\"' && *p != '\'' ) {
1148 return 0;
1149 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001150
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 char endTag[2] = { *p, 0 };
1152 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001153
Lee Thomason624d43f2012-10-12 10:58:48 -07001154 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001156}
1157
1158
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001159void XMLAttribute::SetName( const char* n )
1160{
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001162}
1163
1164
Lee Thomason2fa81722012-11-09 12:37:46 -08001165XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 if ( XMLUtil::ToInt( Value(), value )) {
1168 return XML_NO_ERROR;
1169 }
1170 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171}
1172
1173
Lee Thomason2fa81722012-11-09 12:37:46 -08001174XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( XMLUtil::ToUnsigned( Value(), value )) {
1177 return XML_NO_ERROR;
1178 }
1179 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
1181
1182
Lee Thomason2fa81722012-11-09 12:37:46 -08001183XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::ToBool( Value(), value )) {
1186 return XML_NO_ERROR;
1187 }
1188 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189}
1190
1191
Lee Thomason2fa81722012-11-09 12:37:46 -08001192XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 if ( XMLUtil::ToFloat( Value(), value )) {
1195 return XML_NO_ERROR;
1196 }
1197 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001198}
1199
1200
Lee Thomason2fa81722012-11-09 12:37:46 -08001201XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( XMLUtil::ToDouble( Value(), value )) {
1204 return XML_NO_ERROR;
1205 }
1206 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
1210void XMLAttribute::SetAttribute( const char* v )
1211{
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
1214
1215
Lee Thomason1ff38e02012-02-14 18:18:16 -08001216void XMLAttribute::SetAttribute( int v )
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 char buf[BUF_SIZE];
1219 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001221}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001222
1223
1224void XMLAttribute::SetAttribute( unsigned v )
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 char buf[BUF_SIZE];
1227 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231
1232void XMLAttribute::SetAttribute( bool v )
1233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 char buf[BUF_SIZE];
1235 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001237}
1238
1239void XMLAttribute::SetAttribute( double v )
1240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 char buf[BUF_SIZE];
1242 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001244}
1245
1246void XMLAttribute::SetAttribute( float v )
1247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 char buf[BUF_SIZE];
1249 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001251}
1252
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001253
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001254// --------- XMLElement ---------- //
1255XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 _closingType( 0 ),
1257 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001258{
1259}
1260
1261
1262XMLElement::~XMLElement()
1263{
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 while( _rootAttribute ) {
1265 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001266 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269}
1270
1271
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1273{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001274 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1276 return a;
1277 }
1278 }
1279 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001280}
1281
1282
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001283const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 const XMLAttribute* a = FindAttribute( name );
1286 if ( !a ) {
1287 return 0;
1288 }
1289 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1290 return a->Value();
1291 }
1292 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001293}
1294
1295
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296const char* XMLElement::GetText() const
1297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001299 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 }
1301 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001302}
1303
1304
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001305void XMLElement::SetText( const char* inText )
1306{
Uli Kusterer869bb592014-01-21 01:36:16 +01001307 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001308 FirstChild()->SetValue( inText );
1309 else {
1310 XMLText* theText = GetDocument()->NewText( inText );
1311 InsertFirstChild( theText );
1312 }
1313}
1314
Lee Thomason5bb2d802014-01-24 10:42:57 -08001315
1316void XMLElement::SetText( int v )
1317{
1318 char buf[BUF_SIZE];
1319 XMLUtil::ToStr( v, buf, BUF_SIZE );
1320 SetText( buf );
1321}
1322
1323
1324void XMLElement::SetText( unsigned v )
1325{
1326 char buf[BUF_SIZE];
1327 XMLUtil::ToStr( v, buf, BUF_SIZE );
1328 SetText( buf );
1329}
1330
1331
1332void XMLElement::SetText( bool v )
1333{
1334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
1336 SetText( buf );
1337}
1338
1339
1340void XMLElement::SetText( float v )
1341{
1342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
1344 SetText( buf );
1345}
1346
1347
1348void XMLElement::SetText( double v )
1349{
1350 char buf[BUF_SIZE];
1351 XMLUtil::ToStr( v, buf, BUF_SIZE );
1352 SetText( buf );
1353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001359 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001372 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001385 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return XML_SUCCESS;
1388 }
1389 return XML_CAN_NOT_CONVERT_TEXT;
1390 }
1391 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001392}
1393
1394
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001398 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 return XML_SUCCESS;
1401 }
1402 return XML_CAN_NOT_CONVERT_TEXT;
1403 }
1404 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001405}
1406
1407
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001411 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001412 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 return XML_SUCCESS;
1414 }
1415 return XML_CAN_NOT_CONVERT_TEXT;
1416 }
1417 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001418}
1419
1420
1421
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001422XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 XMLAttribute* last = 0;
1425 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1430 break;
1431 }
1432 }
1433 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001434 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1436 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001441 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 }
1443 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001444 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 }
1446 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001447}
1448
1449
U-Stream\Leeae25a442012-02-17 17:48:16 -08001450void XMLElement::DeleteAttribute( const char* name )
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1455 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 }
1458 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001461 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 break;
1463 }
1464 prev = a;
1465 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001466}
1467
1468
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001469char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 const char* start = p;
1472 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001473
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 // Read the attributes.
1475 while( p ) {
1476 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001477 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return 0;
1480 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001483 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001484 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1486 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001487 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001488
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001491 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 return 0;
1494 }
1495 // There is a minor bug here: if the attribute in the source xml
1496 // document is duplicated, it will not be detected and the
1497 // attribute will be doubly added. However, tracking the 'prevAttribute'
1498 // avoids re-scanning the attribute list. Preferring performance for
1499 // now, may reconsider in the future.
1500 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 }
1503 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 }
1506 prevAttribute = attrib;
1507 }
1508 // end of the tag
1509 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return p+2; // done; sealed element.
1512 }
1513 // end of the tag
1514 else if ( *p == '>' ) {
1515 ++p;
1516 break;
1517 }
1518 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 return 0;
1521 }
1522 }
1523 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001524}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Dmitry-Mee3225b12014-09-03 11:03:11 +04001526void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1527{
1528 if ( attribute == 0 ) {
1529 return;
1530 }
1531 MemPool* pool = attribute->_memPool;
1532 attribute->~XMLAttribute();
1533 pool->Free( attribute );
1534}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001535
Lee Thomason67d61312012-01-24 16:01:51 -08001536//
1537// <ele></ele>
1538// <ele>foo<b>bar</b></ele>
1539//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001540char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // Read the element name.
1543 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001544
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 // The closing element is the </element> form. It is
1546 // parsed just like a regular element then deleted from
1547 // the DOM.
1548 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 ++p;
1551 }
Lee Thomason67d61312012-01-24 16:01:51 -08001552
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 p = _value.ParseName( p );
1554 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 return 0;
1556 }
Lee Thomason67d61312012-01-24 16:01:51 -08001557
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 return p;
1561 }
Lee Thomason67d61312012-01-24 16:01:51 -08001562
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 p = XMLNode::ParseDeep( p, strPair );
1564 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001565}
1566
1567
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001568
1569XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 }
1574 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1575 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1576 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1577 }
1578 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579}
1580
1581
1582bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1583{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001584 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 const XMLElement* other = compare->ToElement();
1586 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 const XMLAttribute* a=FirstAttribute();
1589 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 while ( a && b ) {
1592 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1593 return false;
1594 }
1595 a = a->Next();
1596 b = b->Next();
1597 }
1598 if ( a || b ) {
1599 // different count
1600 return false;
1601 }
1602 return true;
1603 }
1604 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001605}
1606
1607
Lee Thomason751da522012-02-10 08:50:51 -08001608bool XMLElement::Accept( XMLVisitor* visitor ) const
1609{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001610 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001612 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1613 if ( !node->Accept( visitor ) ) {
1614 break;
1615 }
1616 }
1617 }
1618 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001619}
Lee Thomason56bdd022012-02-09 18:16:58 -08001620
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001621
Lee Thomason3f57d272012-01-11 15:30:03 -08001622// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001623
1624// Warning: List must match 'enum XMLError'
1625const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1626 "XML_SUCCESS",
1627 "XML_NO_ATTRIBUTE",
1628 "XML_WRONG_ATTRIBUTE_TYPE",
1629 "XML_ERROR_FILE_NOT_FOUND",
1630 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1631 "XML_ERROR_FILE_READ_ERROR",
1632 "XML_ERROR_ELEMENT_MISMATCH",
1633 "XML_ERROR_PARSING_ELEMENT",
1634 "XML_ERROR_PARSING_ATTRIBUTE",
1635 "XML_ERROR_IDENTIFYING_TAG",
1636 "XML_ERROR_PARSING_TEXT",
1637 "XML_ERROR_PARSING_CDATA",
1638 "XML_ERROR_PARSING_COMMENT",
1639 "XML_ERROR_PARSING_DECLARATION",
1640 "XML_ERROR_PARSING_UNKNOWN",
1641 "XML_ERROR_EMPTY_DOCUMENT",
1642 "XML_ERROR_MISMATCHED_ELEMENT",
1643 "XML_ERROR_PARSING",
1644 "XML_CAN_NOT_CONVERT_TEXT",
1645 "XML_NO_TEXT_NODE"
1646};
1647
1648
Lee Thomason624d43f2012-10-12 10:58:48 -07001649XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _writeBOM( false ),
1652 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001653 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _whitespace( whitespace ),
1655 _errorStr1( 0 ),
1656 _errorStr2( 0 ),
1657 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001658{
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001660}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001661
1662
Lee Thomason3f57d272012-01-11 15:30:03 -08001663XMLDocument::~XMLDocument()
1664{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001665 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001666}
1667
1668
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001669void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001670{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001671 DeleteChildren();
1672
Dmitry-Meab37df82014-11-28 12:08:36 +03001673#ifdef DEBUG
1674 const bool hadError = Error();
1675#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 _errorID = XML_NO_ERROR;
1677 _errorStr1 = 0;
1678 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001679
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 delete [] _charBuffer;
1681 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001682
1683#if 0
1684 _textPool.Trace( "text" );
1685 _elementPool.Trace( "element" );
1686 _commentPool.Trace( "comment" );
1687 _attributePool.Trace( "attribute" );
1688#endif
1689
1690#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001691 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001692 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1693 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1694 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1695 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1696 }
1697#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001698}
1699
Lee Thomason3f57d272012-01-11 15:30:03 -08001700
Lee Thomason2c85a712012-01-31 08:24:24 -08001701XMLElement* XMLDocument::NewElement( const char* name )
1702{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001703 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001704 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1705 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 ele->SetName( name );
1707 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001708}
1709
1710
Lee Thomason1ff38e02012-02-14 18:18:16 -08001711XMLComment* XMLDocument::NewComment( const char* str )
1712{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001713 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1715 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 comment->SetValue( str );
1717 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001718}
1719
1720
1721XMLText* XMLDocument::NewText( const char* str )
1722{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001723 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1725 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 text->SetValue( str );
1727 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001728}
1729
1730
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001731XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1732{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001733 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1735 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1737 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001738}
1739
1740
1741XMLUnknown* XMLDocument::NewUnknown( const char* str )
1742{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001743 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1745 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 unk->SetValue( str );
1747 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001748}
1749
Dmitry-Me01578db2014-08-19 10:18:48 +04001750static FILE* callfopen( const char* filepath, const char* mode )
1751{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001752 TIXMLASSERT( filepath );
1753 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001754#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1755 FILE* fp = 0;
1756 errno_t err = fopen_s( &fp, filepath, mode );
1757 if ( err ) {
1758 return 0;
1759 }
1760#else
1761 FILE* fp = fopen( filepath, mode );
1762#endif
1763 return fp;
1764}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001765
1766void XMLDocument::DeleteNode( XMLNode* node ) {
1767 TIXMLASSERT( node );
1768 TIXMLASSERT(node->_document == this );
1769 if (node->_parent) {
1770 node->_parent->DeleteChild( node );
1771 }
1772 else {
1773 // Isn't in the tree.
1774 // Use the parent delete.
1775 // Also, we need to mark it tracked: we 'know'
1776 // it was never used.
1777 node->_memPool->SetTracked();
1778 // Call the static XMLNode version:
1779 XMLNode::DeleteNode(node);
1780 }
1781}
1782
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001783
Lee Thomason2fa81722012-11-09 12:37:46 -08001784XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001785{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001786 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001787 FILE* fp = callfopen( filename, "rb" );
1788 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 }
1792 LoadFile( fp );
1793 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795}
1796
1797
Lee Thomason2fa81722012-11-09 12:37:46 -08001798XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001799{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001800 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001801
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001802 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001803 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001804 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1805 return _errorID;
1806 }
1807
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001809 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001811 if ( filelength == -1L ) {
1812 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1813 return _errorID;
1814 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001815
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001816 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001818 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001821
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 _charBuffer = new char[size+1];
1823 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 if ( read != size ) {
1825 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001828
Lee Thomason624d43f2012-10-12 10:58:48 -07001829 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001830
Dmitry-Me97476b72015-01-01 16:15:57 +03001831 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833}
1834
1835
Lee Thomason2fa81722012-11-09 12:37:46 -08001836XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837{
Dmitry-Me01578db2014-08-19 10:18:48 +04001838 FILE* fp = callfopen( filename, "w" );
1839 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 }
1843 SaveFile(fp, compact);
1844 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001846}
1847
1848
Lee Thomason2fa81722012-11-09 12:37:46 -08001849XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001850{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 XMLPrinter stream( fp, compact );
1852 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001854}
1855
Lee Thomason1ff38e02012-02-14 18:18:16 -08001856
Lee Thomason2fa81722012-11-09 12:37:46 -08001857XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001858{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001859 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001860
Lee Thomason82d32002014-02-21 22:47:18 -08001861 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 }
1865 if ( len == (size_t)(-1) ) {
1866 len = strlen( p );
1867 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 _charBuffer = new char[ len+1 ];
1869 memcpy( _charBuffer, p, len );
1870 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001871
Dmitry-Me97476b72015-01-01 16:15:57 +03001872 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001873 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001874 // clean up now essentially dangling memory.
1875 // and the parse fail can put objects in the
1876 // pools that are dead and inaccessible.
1877 DeleteChildren();
1878 _elementPool.Clear();
1879 _attributePool.Clear();
1880 _textPool.Clear();
1881 _commentPool.Clear();
1882 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001884}
1885
1886
PKEuS1c5f99e2013-07-06 11:28:39 +02001887void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001888{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 XMLPrinter stdStreamer( stdout );
1890 if ( !streamer ) {
1891 streamer = &stdStreamer;
1892 }
1893 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001894}
1895
1896
Lee Thomason2fa81722012-11-09 12:37:46 -08001897void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001898{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001899 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 _errorID = error;
1901 _errorStr1 = str1;
1902 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001903}
1904
Lee Thomason331596e2014-09-11 14:56:43 -07001905const char* XMLDocument::ErrorName() const
1906{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001907 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001908 return _errorNames[_errorID];
1909}
Lee Thomason5cae8972012-01-24 18:03:07 -08001910
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001911void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001913 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 static const int LEN = 20;
1915 char buf1[LEN] = { 0 };
1916 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001917
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 if ( _errorStr1 ) {
1919 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 if ( _errorStr2 ) {
1922 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001924
Lee Thomason331596e2014-09-11 14:56:43 -07001925 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1926 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001928}
1929
Dmitry-Me97476b72015-01-01 16:15:57 +03001930void XMLDocument::Parse()
1931{
1932 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1933 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001934 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001935 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001936 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001937 if ( !*p ) {
1938 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1939 return;
1940 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001941 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001942}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943
PKEuS1bfb9542013-08-04 13:51:17 +02001944XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 _elementJustOpened( false ),
1946 _firstElement( true ),
1947 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001948 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _textDepth( -1 ),
1950 _processEntities( true ),
1951 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 _entityFlag[i] = false;
1955 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 }
1957 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001958 const char entityValue = entities[i].value;
1959 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1960 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001962 _restrictedEntityFlag[(unsigned char)'&'] = true;
1963 _restrictedEntityFlag[(unsigned char)'<'] = true;
1964 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001965 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001966}
1967
1968
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001969void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001970{
1971 va_list va;
1972 va_start( va, format );
1973
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 if ( _fp ) {
1975 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 }
1977 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001978#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001979 #if defined(WINCE)
1980 int len = 512;
1981 do {
1982 len = len*2;
1983 char* str = new char[len]();
1984 len = _vsnprintf(str, len, format, va);
1985 delete[] str;
1986 }while (len < 0);
1987 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001988 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001989 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990#else
1991 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001992#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001993 // Close out and re-start the va-args
1994 va_end( va );
1995 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001996 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1997#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001998 #if defined(WINCE)
1999 _vsnprintf( p, len+1, format, va );
2000 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002001 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002002 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002003#else
2004 vsnprintf( p, len+1, format, va );
2005#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002007 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002008}
2009
2010
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002011void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002012{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 for( int i=0; i<depth; ++i ) {
2014 Print( " " );
2015 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002016}
2017
2018
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002019void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002020{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 // Look for runs of bytes between entities to print.
2022 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002024
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 while ( *q ) {
2027 // Remember, char is sometimes signed. (How many times has that bitten me?)
2028 if ( *q > 0 && *q < ENTITY_RANGE ) {
2029 // Check for entities. If one is found, flush
2030 // the stream up until the entity, write the
2031 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002032 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 while ( p < q ) {
2034 Print( "%c", *p );
2035 ++p;
2036 }
2037 for( int i=0; i<NUM_ENTITIES; ++i ) {
2038 if ( entities[i].value == *q ) {
2039 Print( "&%s;", entities[i].pattern );
2040 break;
2041 }
2042 }
2043 ++p;
2044 }
2045 }
2046 ++q;
2047 }
2048 }
2049 // Flush the remaining string. This will be the entire
2050 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( "%s", p );
2053 }
Lee Thomason857b8682012-01-25 17:50:25 -08002054}
2055
U-Stream\Leeae25a442012-02-17 17:48:16 -08002056
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002057void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002058{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002060 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 -07002061 Print( "%s", bom );
2062 }
2063 if ( writeDec ) {
2064 PushDeclaration( "xml version=\"1.0\"" );
2065 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002066}
2067
2068
Uli Kusterer593a33d2014-02-01 12:48:51 +01002069void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002070{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002071 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002073
Uli Kusterer593a33d2014-02-01 12:48:51 +01002074 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002076 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002077 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002080
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 _elementJustOpened = true;
2083 _firstElement = false;
2084 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002085}
2086
2087
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002088void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002089{
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 Print( " %s=\"", name );
2092 PrintString( value, false );
2093 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002094}
2095
2096
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002097void XMLPrinter::PushAttribute( const char* name, int v )
2098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 char buf[BUF_SIZE];
2100 XMLUtil::ToStr( v, buf, BUF_SIZE );
2101 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102}
2103
2104
2105void XMLPrinter::PushAttribute( const char* name, unsigned v )
2106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 char buf[BUF_SIZE];
2108 XMLUtil::ToStr( v, buf, BUF_SIZE );
2109 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002110}
2111
2112
2113void XMLPrinter::PushAttribute( const char* name, bool v )
2114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 char buf[BUF_SIZE];
2116 XMLUtil::ToStr( v, buf, BUF_SIZE );
2117 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002118}
2119
2120
2121void XMLPrinter::PushAttribute( const char* name, double v )
2122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 char buf[BUF_SIZE];
2124 XMLUtil::ToStr( v, buf, BUF_SIZE );
2125 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002126}
2127
2128
Uli Kustererca412e82014-02-01 13:35:05 +01002129void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002130{
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 --_depth;
2132 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002133
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "/>" );
2136 }
2137 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002138 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 }
2142 Print( "</%s>", name );
2143 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002144
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 if ( _textDepth == _depth ) {
2146 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 }
Uli Kustererca412e82014-02-01 13:35:05 +01002148 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 Print( "\n" );
2150 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002152}
2153
2154
Dmitry-Mea092bc12014-12-23 17:57:05 +03002155void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002156{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002157 if ( !_elementJustOpened ) {
2158 return;
2159 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002162}
2163
2164
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002165void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002166{
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002168
Dmitry-Mea092bc12014-12-23 17:57:05 +03002169 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 if ( cdata ) {
2171 Print( "<![CDATA[" );
2172 Print( "%s", text );
2173 Print( "]]>" );
2174 }
2175 else {
2176 PrintString( text, true );
2177 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002178}
2179
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002180void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 char buf[BUF_SIZE];
2183 XMLUtil::ToStr( value, buf, BUF_SIZE );
2184 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002185}
2186
2187
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002188void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 char buf[BUF_SIZE];
2191 XMLUtil::ToStr( value, buf, BUF_SIZE );
2192 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002193}
2194
2195
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002196void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 char buf[BUF_SIZE];
2199 XMLUtil::ToStr( value, buf, BUF_SIZE );
2200 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002201}
2202
2203
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002204void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 char buf[BUF_SIZE];
2207 XMLUtil::ToStr( value, buf, BUF_SIZE );
2208 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002209}
2210
2211
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002212void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 char buf[BUF_SIZE];
2215 XMLUtil::ToStr( value, buf, BUF_SIZE );
2216 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002217}
2218
Lee Thomason5cae8972012-01-24 18:03:07 -08002219
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002220void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002221{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002222 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002229}
Lee Thomason751da522012-02-10 08:50:51 -08002230
2231
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002232void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002233{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002234 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241}
2242
2243
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002244void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002245{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002246 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002253}
2254
2255
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002256bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002257{
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 if ( doc.HasBOM() ) {
2260 PushHeader( true, false );
2261 }
2262 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002263}
2264
2265
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002266bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002267{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002268 const XMLElement* parentElem = element.Parent()->ToElement();
2269 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2270 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 while ( attribute ) {
2272 PushAttribute( attribute->Name(), attribute->Value() );
2273 attribute = attribute->Next();
2274 }
2275 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002276}
2277
2278
Uli Kustererca412e82014-02-01 13:35:05 +01002279bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002280{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002281 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002283}
2284
2285
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002286bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 PushText( text.Value(), text.CData() );
2289 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002290}
2291
2292
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002293bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 PushComment( comment.Value() );
2296 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002297}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002299bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 PushDeclaration( declaration.Value() );
2302 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303}
2304
2305
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002306bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 PushUnknown( unknown.Value() );
2309 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002310}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002311
Lee Thomason685b8952012-11-12 13:00:06 -08002312} // namespace tinyxml2
2313