blob: 46f5f7fd94267637ab2f78d46682a9b397516427 [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;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300354 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 ptrdiff_t delta = 0;
356 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800357 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 if ( *(p+2) == 'x' ) {
360 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300361 const char* q = p+3;
362 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Dmitry-Me9f56e122015-01-12 10:07:54 +0300368 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 return 0;
370 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800371 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != 'x' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else if ( *q >= 'a' && *q <= 'f' ) {
381 ucs += mult * (*q - 'a' + 10);
382 }
383 else if ( *q >= 'A' && *q <= 'F' ) {
384 ucs += mult * (*q - 'A' + 10 );
385 }
386 else {
387 return 0;
388 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300389 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 mult *= 16;
391 --q;
392 }
393 }
394 else {
395 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300396 const char* q = p+2;
397 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return 0;
399 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Lee Thomason7e67bc82015-01-12 14:05:12 -0800401 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Dmitry-Me9f56e122015-01-12 10:07:54 +0300403 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return 0;
405 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800406 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 delta = q-p;
409 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 while ( *q != '#' ) {
412 if ( *q >= '0' && *q <= '9' ) {
413 ucs += mult * (*q - '0');
414 }
415 else {
416 return 0;
417 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300418 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 mult *= 10;
420 --q;
421 }
422 }
423 // convert the UCS to UTF-8
424 ConvertUTF32ToUTF8( ucs, value, length );
425 return p + delta + 1;
426 }
427 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800429
430
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700431void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
442
443void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448/*
449 ToStr() of a number is a very tricky topic.
450 https://github.com/leethomason/tinyxml2/issues/106
451*/
Lee Thomason21be8822012-07-15 17:27:22 -0700452void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
459{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800460 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464bool XMLUtil::ToInt( const char* str, int* value )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700474 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
475 return true;
476 }
477 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700478}
479
480bool XMLUtil::ToBool( const char* str, bool* value )
481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 int ival = 0;
483 if ( ToInt( str, &ival )) {
484 *value = (ival==0) ? false : true;
485 return true;
486 }
487 if ( StringEqual( str, "true" ) ) {
488 *value = true;
489 return true;
490 }
491 else if ( StringEqual( str, "false" ) ) {
492 *value = false;
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498
499bool XMLUtil::ToFloat( const char* str, float* value )
500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
502 return true;
503 }
504 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700505}
506
507bool XMLUtil::ToDouble( const char* str, double* value )
508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
510 return true;
511 }
512 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700513}
514
515
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700516char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517{
Dmitry-Me02384662015-03-03 16:02:13 +0300518 TIXMLASSERT( node );
519 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400520 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300522 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 return p;
524 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800527 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 static const char* xmlHeader = { "<?" };
529 static const char* commentHeader = { "<!--" };
530 static const char* dtdHeader = { "<!" };
531 static const char* cdataHeader = { "<![CDATA[" };
532 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800533
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 static const int xmlHeaderLen = 2;
535 static const int commentHeaderLen = 4;
536 static const int dtdHeaderLen = 2;
537 static const int cdataHeaderLen = 9;
538 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800539
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
541 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400542 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300544 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += xmlHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300550 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode = new (_commentPool.Alloc()) XMLComment( this );
552 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += commentHeaderLen;
554 }
555 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300556 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p += cdataHeaderLen;
561 text->SetCData( true );
562 }
563 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300564 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700565 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
566 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 p += dtdHeaderLen;
568 }
569 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300570 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700571 returnNode = new (_elementPool.Alloc()) XMLElement( this );
572 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 p += elementHeaderLen;
574 }
575 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300576 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700577 returnNode = new (_textPool.Alloc()) XMLText( this );
578 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 p = start; // Back it up, all the text counts.
580 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800581
Dmitry-Me02384662015-03-03 16:02:13 +0300582 TIXMLASSERT( returnNode );
583 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 *node = returnNode;
585 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586}
587
588
Lee Thomason751da522012-02-10 08:50:51 -0800589bool XMLDocument::Accept( XMLVisitor* visitor ) const
590{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300591 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 if ( visitor->VisitEnter( *this ) ) {
593 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
594 if ( !node->Accept( visitor ) ) {
595 break;
596 }
597 }
598 }
599 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800600}
Lee Thomason56bdd022012-02-09 18:16:58 -0800601
602
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800603// --------- XMLNode ----------- //
604
605XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _document( doc ),
607 _parent( 0 ),
608 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200609 _prev( 0 ), _next( 0 ),
610 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800611{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800612}
613
614
615XMLNode::~XMLNode()
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 if ( _parent ) {
619 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800621}
622
Michael Daumling21626882013-10-22 17:03:37 +0200623const char* XMLNode::Value() const
624{
625 return _value.GetStr();
626}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800627
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800628void XMLNode::SetValue( const char* str, bool staticMem )
629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 }
633 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800636}
637
638
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800639void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800640{
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300642 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700645
Dmitry-Mee3225b12014-09-03 11:03:11 +0400646 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800649}
650
651
652void XMLNode::Unlink( XMLNode* child )
653{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300654 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300655 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 if ( child == _firstChild ) {
657 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( child == _lastChild ) {
660 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomasond923c672012-01-23 08:44:25 -0800662
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 if ( child->_prev ) {
664 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 if ( child->_next ) {
667 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700669 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670}
671
672
U-Stream\Leeae25a442012-02-17 17:48:16 -0800673void XMLNode::DeleteChild( XMLNode* node )
674{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300675 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300676 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400678 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800679}
680
681
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
683{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300684 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300685 if ( addThis->_document != _document ) {
686 TIXMLASSERT( false );
687 return 0;
688 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800689 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700690
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 if ( _lastChild ) {
692 TIXMLASSERT( _firstChild );
693 TIXMLASSERT( _lastChild->_next == 0 );
694 _lastChild->_next = addThis;
695 addThis->_prev = _lastChild;
696 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Lee Thomason624d43f2012-10-12 10:58:48 -0700698 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 }
700 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 TIXMLASSERT( _firstChild == 0 );
702 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800703
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 addThis->_prev = 0;
705 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800709}
710
711
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
713{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300714 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300715 if ( addThis->_document != _document ) {
716 TIXMLASSERT( false );
717 return 0;
718 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800719 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 if ( _firstChild ) {
722 TIXMLASSERT( _lastChild );
723 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 _firstChild->_prev = addThis;
726 addThis->_next = _firstChild;
727 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 }
731 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 TIXMLASSERT( _lastChild == 0 );
733 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 addThis->_prev = 0;
736 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400739 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800740}
741
742
743XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
744{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300745 TIXMLASSERT( addThis );
746 if ( addThis->_document != _document ) {
747 TIXMLASSERT( false );
748 return 0;
749 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700750
Dmitry-Meabb2d042014-12-09 12:59:31 +0300751 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700752
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300754 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 return 0;
756 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800757
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 // The last node or the only node.
760 return InsertEndChild( addThis );
761 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800762 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 addThis->_prev = afterThis;
764 addThis->_next = afterThis->_next;
765 afterThis->_next->_prev = addThis;
766 afterThis->_next = addThis;
767 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800769}
770
771
772
773
Lee Thomason56bdd022012-02-09 18:16:58 -0800774const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800775{
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 XMLElement* element = node->ToElement();
778 if ( element ) {
779 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
780 return element;
781 }
782 }
783 }
784 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800785}
786
787
Lee Thomason56bdd022012-02-09 18:16:58 -0800788const XMLElement* XMLNode::LastChildElement( const char* value ) const
789{
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 XMLElement* element = node->ToElement();
792 if ( element ) {
793 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
794 return element;
795 }
796 }
797 }
798 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800799}
800
801
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800802const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
803{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400804 for( XMLNode* node=this->_next; node; node = node->_next ) {
805 const XMLElement* element = node->ToElement();
806 if ( element
807 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
808 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
810 }
811 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800812}
813
814
815const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
816{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400817 for( XMLNode* node=_prev; node; node = node->_prev ) {
818 const XMLElement* element = node->ToElement();
819 if ( element
820 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
821 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 }
824 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800825}
826
827
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800828char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 // This is a recursive method, but thinking about it "at the current level"
831 // it is a pretty simple flat list:
832 // <foo/>
833 // <!-- comment -->
834 //
835 // With a special case:
836 // <foo>
837 // </foo>
838 // <!-- comment -->
839 //
840 // Where the closing element (/foo) *must* be the next thing after the opening
841 // element, and the names must match. BUT the tricky bit is that the closing
842 // element will be read by the child.
843 //
844 // 'endTag' is the end tag for this node, it is returned by a call to a child.
845 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 while( p && *p ) {
848 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 p = _document->Identify( p, &node );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800851
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 StrPair endTag;
853 p = node->ParseDeep( p, &endTag );
854 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400855 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 if ( !_document->Error() ) {
857 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 break;
860 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800861
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400862 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500864 // We read the end tag. Return it to the parent.
865 if ( ele->ClosingType() == XMLElement::CLOSING ) {
866 if ( parentEnd ) {
867 ele->_value.TransferTo( parentEnd );
868 }
869 node->_memPool->SetTracked(); // created and then immediately deleted.
870 DeleteNode( node );
871 return p;
872 }
873
874 // Handle an end tag returned to this level.
875 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400876 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300877 if ( endTag.Empty() ) {
878 if ( ele->ClosingType() == XMLElement::OPEN ) {
879 mismatch = true;
880 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300882 else {
883 if ( ele->ClosingType() != XMLElement::OPEN ) {
884 mismatch = true;
885 }
886 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400887 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400890 if ( mismatch ) {
891 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500892 DeleteNode( node );
893 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
JayXondbfdd8f2014-12-12 20:07:14 -0500896 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 }
898 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800899}
900
Dmitry-Mee3225b12014-09-03 11:03:11 +0400901void XMLNode::DeleteNode( XMLNode* node )
902{
903 if ( node == 0 ) {
904 return;
905 }
906 MemPool* pool = node->_memPool;
907 node->~XMLNode();
908 pool->Free( node );
909}
910
Lee Thomason3cebdc42015-01-05 17:16:28 -0800911void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300912{
913 TIXMLASSERT( insertThis );
914 TIXMLASSERT( insertThis->_document == _document );
915
916 if ( insertThis->_parent )
917 insertThis->_parent->Unlink( insertThis );
918 else
919 insertThis->_memPool->SetTracked();
920}
921
Lee Thomason5492a1c2012-01-23 15:32:10 -0800922// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800923char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800924{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 const char* start = p;
926 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700927 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 }
931 return p;
932 }
933 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
935 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 flags |= StrPair::COLLAPSE_WHITESPACE;
937 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700938
Lee Thomason624d43f2012-10-12 10:58:48 -0700939 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 if ( p && *p ) {
941 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300942 }
943 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300944 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800948}
949
950
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
957 text->SetCData( this->CData() );
958 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959}
960
961
962bool XMLText::ShallowEqual( const XMLNode* compare ) const
963{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400964 const XMLText* text = compare->ToText();
965 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800966}
967
968
Lee Thomason56bdd022012-02-09 18:16:58 -0800969bool XMLText::Accept( XMLVisitor* visitor ) const
970{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300971 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700972 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800973}
974
975
Lee Thomason3f57d272012-01-11 15:30:03 -0800976// --------- XMLComment ---------- //
977
Lee Thomasone4422302012-01-20 17:59:50 -0800978XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
980}
981
982
Lee Thomasonce0763e2012-01-11 15:43:54 -0800983XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800984{
Lee Thomason3f57d272012-01-11 15:30:03 -0800985}
986
987
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800988char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 // Comment parses as text.
991 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
996 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800997}
998
999
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001000XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001003 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1006 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
1010bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1011{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001012 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001013 const XMLComment* comment = compare->ToComment();
1014 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001015}
1016
1017
Lee Thomason751da522012-02-10 08:50:51 -08001018bool XMLComment::Accept( XMLVisitor* visitor ) const
1019{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001020 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001022}
Lee Thomason56bdd022012-02-09 18:16:58 -08001023
1024
Lee Thomason50f97b22012-02-11 16:33:40 -08001025// --------- XMLDeclaration ---------- //
1026
1027XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1028{
1029}
1030
1031
1032XMLDeclaration::~XMLDeclaration()
1033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001035}
1036
1037
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001038char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 // Declaration parses as text.
1041 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001047}
1048
1049
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001050XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1051{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001053 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 }
1055 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1056 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
1060bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1061{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001062 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001063 const XMLDeclaration* declaration = compare->ToDeclaration();
1064 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001065}
1066
1067
1068
Lee Thomason50f97b22012-02-11 16:33:40 -08001069bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1070{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001071 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001073}
1074
1075// --------- XMLUnknown ---------- //
1076
1077XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1078{
1079}
1080
1081
1082XMLUnknown::~XMLUnknown()
1083{
1084}
1085
1086
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001087char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 // Unknown parses as text.
1090 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001091
Lee Thomason624d43f2012-10-12 10:58:48 -07001092 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001094 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 }
1096 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001097}
1098
1099
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001100XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001103 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
1105 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1106 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001107}
1108
1109
1110bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1111{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001112 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001113 const XMLUnknown* unknown = compare->ToUnknown();
1114 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001115}
1116
1117
Lee Thomason50f97b22012-02-11 16:33:40 -08001118bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1119{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001120 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001122}
1123
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001124// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001125
1126const char* XMLAttribute::Name() const
1127{
1128 return _name.GetStr();
1129}
1130
1131const char* XMLAttribute::Value() const
1132{
1133 return _value.GetStr();
1134}
1135
Lee Thomason6f381b72012-03-02 12:59:39 -08001136char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 if ( !p || !*p ) {
1141 return 0;
1142 }
Lee Thomason22aead12012-01-23 13:29:35 -08001143
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 // Skip white space before =
1145 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001146 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 return 0;
1148 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001149
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 ++p; // move up to opening quote
1151 p = XMLUtil::SkipWhiteSpace( p );
1152 if ( *p != '\"' && *p != '\'' ) {
1153 return 0;
1154 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001155
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 char endTag[2] = { *p, 0 };
1157 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001158
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001161}
1162
1163
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001164void XMLAttribute::SetName( const char* n )
1165{
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001167}
1168
1169
Lee Thomason2fa81722012-11-09 12:37:46 -08001170XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 if ( XMLUtil::ToInt( Value(), value )) {
1173 return XML_NO_ERROR;
1174 }
1175 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176}
1177
1178
Lee Thomason2fa81722012-11-09 12:37:46 -08001179XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 if ( XMLUtil::ToUnsigned( Value(), value )) {
1182 return XML_NO_ERROR;
1183 }
1184 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185}
1186
1187
Lee Thomason2fa81722012-11-09 12:37:46 -08001188XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 if ( XMLUtil::ToBool( Value(), value )) {
1191 return XML_NO_ERROR;
1192 }
1193 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001194}
1195
1196
Lee Thomason2fa81722012-11-09 12:37:46 -08001197XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 if ( XMLUtil::ToFloat( Value(), value )) {
1200 return XML_NO_ERROR;
1201 }
1202 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001203}
1204
1205
Lee Thomason2fa81722012-11-09 12:37:46 -08001206XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 if ( XMLUtil::ToDouble( Value(), value )) {
1209 return XML_NO_ERROR;
1210 }
1211 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212}
1213
1214
1215void XMLAttribute::SetAttribute( const char* v )
1216{
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218}
1219
1220
Lee Thomason1ff38e02012-02-14 18:18:16 -08001221void XMLAttribute::SetAttribute( int v )
1222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 char buf[BUF_SIZE];
1224 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001226}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227
1228
1229void XMLAttribute::SetAttribute( unsigned v )
1230{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 char buf[BUF_SIZE];
1232 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001234}
1235
1236
1237void XMLAttribute::SetAttribute( bool v )
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 char buf[BUF_SIZE];
1240 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001242}
1243
1244void XMLAttribute::SetAttribute( double v )
1245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 char buf[BUF_SIZE];
1247 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001249}
1250
1251void XMLAttribute::SetAttribute( float v )
1252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 char buf[BUF_SIZE];
1254 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001256}
1257
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001258
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001259// --------- XMLElement ---------- //
1260XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _closingType( 0 ),
1262 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001263{
1264}
1265
1266
1267XMLElement::~XMLElement()
1268{
Lee Thomason624d43f2012-10-12 10:58:48 -07001269 while( _rootAttribute ) {
1270 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001271 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001272 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001274}
1275
1276
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001277const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1278{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001279 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1281 return a;
1282 }
1283 }
1284 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001285}
1286
1287
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001288const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 const XMLAttribute* a = FindAttribute( name );
1291 if ( !a ) {
1292 return 0;
1293 }
1294 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1295 return a->Value();
1296 }
1297 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001298}
1299
1300
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301const char* XMLElement::GetText() const
1302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001304 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 }
1306 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001307}
1308
1309
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001310void XMLElement::SetText( const char* inText )
1311{
Uli Kusterer869bb592014-01-21 01:36:16 +01001312 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001313 FirstChild()->SetValue( inText );
1314 else {
1315 XMLText* theText = GetDocument()->NewText( inText );
1316 InsertFirstChild( theText );
1317 }
1318}
1319
Lee Thomason5bb2d802014-01-24 10:42:57 -08001320
1321void XMLElement::SetText( int v )
1322{
1323 char buf[BUF_SIZE];
1324 XMLUtil::ToStr( v, buf, BUF_SIZE );
1325 SetText( buf );
1326}
1327
1328
1329void XMLElement::SetText( unsigned v )
1330{
1331 char buf[BUF_SIZE];
1332 XMLUtil::ToStr( v, buf, BUF_SIZE );
1333 SetText( buf );
1334}
1335
1336
1337void XMLElement::SetText( bool v )
1338{
1339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
1341 SetText( buf );
1342}
1343
1344
1345void XMLElement::SetText( float v )
1346{
1347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
1349 SetText( buf );
1350}
1351
1352
1353void XMLElement::SetText( double v )
1354{
1355 char buf[BUF_SIZE];
1356 XMLUtil::ToStr( v, buf, BUF_SIZE );
1357 SetText( buf );
1358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001364 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001377 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001390 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001416 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 return XML_SUCCESS;
1419 }
1420 return XML_CAN_NOT_CONVERT_TEXT;
1421 }
1422 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
1426
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 XMLAttribute* last = 0;
1430 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1435 break;
1436 }
1437 }
1438 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001439 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1441 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 }
1445 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 }
1448 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001449 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
1451 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001452}
1453
1454
U-Stream\Leeae25a442012-02-17 17:48:16 -08001455void XMLElement::DeleteAttribute( const char* name )
1456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001458 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1460 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 }
1463 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001466 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 break;
1468 }
1469 prev = a;
1470 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001471}
1472
1473
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001474char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 const char* start = p;
1477 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001478
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 // Read the attributes.
1480 while( p ) {
1481 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001482 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 return 0;
1485 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001486
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001488 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001489 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1491 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001492 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001493
Lee Thomason624d43f2012-10-12 10:58:48 -07001494 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001496 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 return 0;
1499 }
1500 // There is a minor bug here: if the attribute in the source xml
1501 // document is duplicated, it will not be detected and the
1502 // attribute will be doubly added. However, tracking the 'prevAttribute'
1503 // avoids re-scanning the attribute list. Preferring performance for
1504 // now, may reconsider in the future.
1505 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 }
1508 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 }
1511 prevAttribute = attrib;
1512 }
1513 // end of the tag
1514 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 return p+2; // done; sealed element.
1517 }
1518 // end of the tag
1519 else if ( *p == '>' ) {
1520 ++p;
1521 break;
1522 }
1523 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001524 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 return 0;
1526 }
1527 }
1528 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001529}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001530
Dmitry-Mee3225b12014-09-03 11:03:11 +04001531void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1532{
1533 if ( attribute == 0 ) {
1534 return;
1535 }
1536 MemPool* pool = attribute->_memPool;
1537 attribute->~XMLAttribute();
1538 pool->Free( attribute );
1539}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001540
Lee Thomason67d61312012-01-24 16:01:51 -08001541//
1542// <ele></ele>
1543// <ele>foo<b>bar</b></ele>
1544//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001545char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 // Read the element name.
1548 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 // The closing element is the </element> form. It is
1551 // parsed just like a regular element then deleted from
1552 // the DOM.
1553 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 ++p;
1556 }
Lee Thomason67d61312012-01-24 16:01:51 -08001557
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 p = _value.ParseName( p );
1559 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 return 0;
1561 }
Lee Thomason67d61312012-01-24 16:01:51 -08001562
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001564 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 return p;
1566 }
Lee Thomason67d61312012-01-24 16:01:51 -08001567
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 p = XMLNode::ParseDeep( p, strPair );
1569 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001570}
1571
1572
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001573
1574XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 }
1579 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1580 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1581 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1582 }
1583 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001584}
1585
1586
1587bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1588{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001589 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 const XMLElement* other = compare->ToElement();
1591 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001592
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 const XMLAttribute* a=FirstAttribute();
1594 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001595
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 while ( a && b ) {
1597 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1598 return false;
1599 }
1600 a = a->Next();
1601 b = b->Next();
1602 }
1603 if ( a || b ) {
1604 // different count
1605 return false;
1606 }
1607 return true;
1608 }
1609 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001610}
1611
1612
Lee Thomason751da522012-02-10 08:50:51 -08001613bool XMLElement::Accept( XMLVisitor* visitor ) const
1614{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001615 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1618 if ( !node->Accept( visitor ) ) {
1619 break;
1620 }
1621 }
1622 }
1623 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001624}
Lee Thomason56bdd022012-02-09 18:16:58 -08001625
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001626
Lee Thomason3f57d272012-01-11 15:30:03 -08001627// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001628
1629// Warning: List must match 'enum XMLError'
1630const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1631 "XML_SUCCESS",
1632 "XML_NO_ATTRIBUTE",
1633 "XML_WRONG_ATTRIBUTE_TYPE",
1634 "XML_ERROR_FILE_NOT_FOUND",
1635 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1636 "XML_ERROR_FILE_READ_ERROR",
1637 "XML_ERROR_ELEMENT_MISMATCH",
1638 "XML_ERROR_PARSING_ELEMENT",
1639 "XML_ERROR_PARSING_ATTRIBUTE",
1640 "XML_ERROR_IDENTIFYING_TAG",
1641 "XML_ERROR_PARSING_TEXT",
1642 "XML_ERROR_PARSING_CDATA",
1643 "XML_ERROR_PARSING_COMMENT",
1644 "XML_ERROR_PARSING_DECLARATION",
1645 "XML_ERROR_PARSING_UNKNOWN",
1646 "XML_ERROR_EMPTY_DOCUMENT",
1647 "XML_ERROR_MISMATCHED_ELEMENT",
1648 "XML_ERROR_PARSING",
1649 "XML_CAN_NOT_CONVERT_TEXT",
1650 "XML_NO_TEXT_NODE"
1651};
1652
1653
Lee Thomason624d43f2012-10-12 10:58:48 -07001654XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 _writeBOM( false ),
1657 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001658 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _whitespace( whitespace ),
1660 _errorStr1( 0 ),
1661 _errorStr2( 0 ),
1662 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001663{
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001665}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001666
1667
Lee Thomason3f57d272012-01-11 15:30:03 -08001668XMLDocument::~XMLDocument()
1669{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001670 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001671}
1672
1673
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001674void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001675{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001676 DeleteChildren();
1677
Dmitry-Meab37df82014-11-28 12:08:36 +03001678#ifdef DEBUG
1679 const bool hadError = Error();
1680#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 _errorID = XML_NO_ERROR;
1682 _errorStr1 = 0;
1683 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001684
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 delete [] _charBuffer;
1686 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001687
1688#if 0
1689 _textPool.Trace( "text" );
1690 _elementPool.Trace( "element" );
1691 _commentPool.Trace( "comment" );
1692 _attributePool.Trace( "attribute" );
1693#endif
1694
1695#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001696 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001697 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1698 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1699 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1700 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1701 }
1702#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001703}
1704
Lee Thomason3f57d272012-01-11 15:30:03 -08001705
Lee Thomason2c85a712012-01-31 08:24:24 -08001706XMLElement* XMLDocument::NewElement( const char* name )
1707{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001708 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1710 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 ele->SetName( name );
1712 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001713}
1714
1715
Lee Thomason1ff38e02012-02-14 18:18:16 -08001716XMLComment* XMLDocument::NewComment( const char* str )
1717{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001718 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1720 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 comment->SetValue( str );
1722 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001723}
1724
1725
1726XMLText* XMLDocument::NewText( const char* str )
1727{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001728 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1730 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 text->SetValue( str );
1732 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001733}
1734
1735
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001736XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1737{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001738 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1740 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1742 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001743}
1744
1745
1746XMLUnknown* XMLDocument::NewUnknown( const char* str )
1747{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001748 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1750 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 unk->SetValue( str );
1752 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001753}
1754
Dmitry-Me01578db2014-08-19 10:18:48 +04001755static FILE* callfopen( const char* filepath, const char* mode )
1756{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001757 TIXMLASSERT( filepath );
1758 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001759#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1760 FILE* fp = 0;
1761 errno_t err = fopen_s( &fp, filepath, mode );
1762 if ( err ) {
1763 return 0;
1764 }
1765#else
1766 FILE* fp = fopen( filepath, mode );
1767#endif
1768 return fp;
1769}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001770
1771void XMLDocument::DeleteNode( XMLNode* node ) {
1772 TIXMLASSERT( node );
1773 TIXMLASSERT(node->_document == this );
1774 if (node->_parent) {
1775 node->_parent->DeleteChild( node );
1776 }
1777 else {
1778 // Isn't in the tree.
1779 // Use the parent delete.
1780 // Also, we need to mark it tracked: we 'know'
1781 // it was never used.
1782 node->_memPool->SetTracked();
1783 // Call the static XMLNode version:
1784 XMLNode::DeleteNode(node);
1785 }
1786}
1787
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001788
Lee Thomason2fa81722012-11-09 12:37:46 -08001789XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001790{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001791 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001792 FILE* fp = callfopen( filename, "rb" );
1793 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
1797 LoadFile( fp );
1798 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800}
1801
1802
Lee Thomason2fa81722012-11-09 12:37:46 -08001803XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001804{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001805 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001806
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001807 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001808 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001809 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1810 return _errorID;
1811 }
1812
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001814 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001816 if ( filelength == -1L ) {
1817 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1818 return _errorID;
1819 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001820
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001821 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001823 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001826
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 _charBuffer = new char[size+1];
1828 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 if ( read != size ) {
1830 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001833
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001835
Dmitry-Me97476b72015-01-01 16:15:57 +03001836 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001838}
1839
1840
Lee Thomason2fa81722012-11-09 12:37:46 -08001841XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001842{
Dmitry-Me01578db2014-08-19 10:18:48 +04001843 FILE* fp = callfopen( filename, "w" );
1844 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 }
1848 SaveFile(fp, compact);
1849 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001851}
1852
1853
Lee Thomason2fa81722012-11-09 12:37:46 -08001854XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001855{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 XMLPrinter stream( fp, compact );
1857 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001859}
1860
Lee Thomason1ff38e02012-02-14 18:18:16 -08001861
Lee Thomason2fa81722012-11-09 12:37:46 -08001862XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001863{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001864 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001865
Lee Thomason82d32002014-02-21 22:47:18 -08001866 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
1870 if ( len == (size_t)(-1) ) {
1871 len = strlen( p );
1872 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 _charBuffer = new char[ len+1 ];
1874 memcpy( _charBuffer, p, len );
1875 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001876
Dmitry-Me97476b72015-01-01 16:15:57 +03001877 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001878 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001879 // clean up now essentially dangling memory.
1880 // and the parse fail can put objects in the
1881 // pools that are dead and inaccessible.
1882 DeleteChildren();
1883 _elementPool.Clear();
1884 _attributePool.Clear();
1885 _textPool.Clear();
1886 _commentPool.Clear();
1887 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001888 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001889}
1890
1891
PKEuS1c5f99e2013-07-06 11:28:39 +02001892void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001893{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 XMLPrinter stdStreamer( stdout );
1895 if ( !streamer ) {
1896 streamer = &stdStreamer;
1897 }
1898 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001899}
1900
1901
Lee Thomason2fa81722012-11-09 12:37:46 -08001902void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001903{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001904 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 _errorID = error;
1906 _errorStr1 = str1;
1907 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001908}
1909
Lee Thomason331596e2014-09-11 14:56:43 -07001910const char* XMLDocument::ErrorName() const
1911{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001912 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001913 return _errorNames[_errorID];
1914}
Lee Thomason5cae8972012-01-24 18:03:07 -08001915
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001916void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001917{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001918 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 static const int LEN = 20;
1920 char buf1[LEN] = { 0 };
1921 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001922
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 if ( _errorStr1 ) {
1924 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 if ( _errorStr2 ) {
1927 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001929
Lee Thomason331596e2014-09-11 14:56:43 -07001930 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1931 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001933}
1934
Dmitry-Me97476b72015-01-01 16:15:57 +03001935void XMLDocument::Parse()
1936{
1937 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1938 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001939 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001940 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001941 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001942 if ( !*p ) {
1943 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1944 return;
1945 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001946 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001947}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001948
PKEuS1bfb9542013-08-04 13:51:17 +02001949XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _elementJustOpened( false ),
1951 _firstElement( true ),
1952 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001953 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 _textDepth( -1 ),
1955 _processEntities( true ),
1956 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001957{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 _entityFlag[i] = false;
1960 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 }
1962 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001963 const char entityValue = entities[i].value;
1964 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1965 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001967 _restrictedEntityFlag[(unsigned char)'&'] = true;
1968 _restrictedEntityFlag[(unsigned char)'<'] = true;
1969 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001971}
1972
1973
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001974void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001975{
1976 va_list va;
1977 va_start( va, format );
1978
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 if ( _fp ) {
1980 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 }
1982 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001983#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001984 #if defined(WINCE)
1985 int len = 512;
1986 do {
1987 len = len*2;
1988 char* str = new char[len]();
1989 len = _vsnprintf(str, len, format, va);
1990 delete[] str;
1991 }while (len < 0);
1992 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001993 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001994 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995#else
1996 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001997#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 // Close out and re-start the va-args
1999 va_end( va );
2000 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002001 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002002 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2003#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002004 #if defined(WINCE)
2005 _vsnprintf( p, len+1, format, va );
2006 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002007 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002008 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002009#else
2010 vsnprintf( p, len+1, format, va );
2011#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002013 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002014}
2015
2016
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002017void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002018{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 for( int i=0; i<depth; ++i ) {
2020 Print( " " );
2021 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002022}
2023
2024
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002025void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 // Look for runs of bytes between entities to print.
2028 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002029
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002031 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 while ( *q ) {
2033 // Remember, char is sometimes signed. (How many times has that bitten me?)
2034 if ( *q > 0 && *q < ENTITY_RANGE ) {
2035 // Check for entities. If one is found, flush
2036 // the stream up until the entity, write the
2037 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002038 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 while ( p < q ) {
2040 Print( "%c", *p );
2041 ++p;
2042 }
2043 for( int i=0; i<NUM_ENTITIES; ++i ) {
2044 if ( entities[i].value == *q ) {
2045 Print( "&%s;", entities[i].pattern );
2046 break;
2047 }
2048 }
2049 ++p;
2050 }
2051 }
2052 ++q;
2053 }
2054 }
2055 // Flush the remaining string. This will be the entire
2056 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002057 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 Print( "%s", p );
2059 }
Lee Thomason857b8682012-01-25 17:50:25 -08002060}
2061
U-Stream\Leeae25a442012-02-17 17:48:16 -08002062
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002063void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002064{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002066 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 -07002067 Print( "%s", bom );
2068 }
2069 if ( writeDec ) {
2070 PushDeclaration( "xml version=\"1.0\"" );
2071 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002072}
2073
2074
Uli Kusterer593a33d2014-02-01 12:48:51 +01002075void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002076{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002077 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002079
Uli Kusterer593a33d2014-02-01 12:48:51 +01002080 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002082 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002083 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002086
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002088 _elementJustOpened = true;
2089 _firstElement = false;
2090 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002091}
2092
2093
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002094void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002095{
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 Print( " %s=\"", name );
2098 PrintString( value, false );
2099 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002100}
2101
2102
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103void XMLPrinter::PushAttribute( const char* name, int v )
2104{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 char buf[BUF_SIZE];
2106 XMLUtil::ToStr( v, buf, BUF_SIZE );
2107 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108}
2109
2110
2111void XMLPrinter::PushAttribute( const char* name, unsigned v )
2112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 char buf[BUF_SIZE];
2114 XMLUtil::ToStr( v, buf, BUF_SIZE );
2115 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002116}
2117
2118
2119void XMLPrinter::PushAttribute( const char* name, bool v )
2120{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 char buf[BUF_SIZE];
2122 XMLUtil::ToStr( v, buf, BUF_SIZE );
2123 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002124}
2125
2126
2127void XMLPrinter::PushAttribute( const char* name, double v )
2128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 char buf[BUF_SIZE];
2130 XMLUtil::ToStr( v, buf, BUF_SIZE );
2131 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002132}
2133
2134
Uli Kustererca412e82014-02-01 13:35:05 +01002135void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002136{
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 --_depth;
2138 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002139
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 Print( "/>" );
2142 }
2143 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002144 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 }
2148 Print( "</%s>", name );
2149 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002150
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 if ( _textDepth == _depth ) {
2152 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
Uli Kustererca412e82014-02-01 13:35:05 +01002154 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 Print( "\n" );
2156 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002158}
2159
2160
Dmitry-Mea092bc12014-12-23 17:57:05 +03002161void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002162{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002163 if ( !_elementJustOpened ) {
2164 return;
2165 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002168}
2169
2170
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002171void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002172{
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002174
Dmitry-Mea092bc12014-12-23 17:57:05 +03002175 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 if ( cdata ) {
2177 Print( "<![CDATA[" );
2178 Print( "%s", text );
2179 Print( "]]>" );
2180 }
2181 else {
2182 PrintString( text, true );
2183 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002184}
2185
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002186void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 char buf[BUF_SIZE];
2189 XMLUtil::ToStr( value, buf, BUF_SIZE );
2190 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002191}
2192
2193
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002194void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 char buf[BUF_SIZE];
2197 XMLUtil::ToStr( value, buf, BUF_SIZE );
2198 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002199}
2200
2201
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002202void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 char buf[BUF_SIZE];
2205 XMLUtil::ToStr( value, buf, BUF_SIZE );
2206 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002207}
2208
2209
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002210void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 char buf[BUF_SIZE];
2213 XMLUtil::ToStr( value, buf, BUF_SIZE );
2214 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002215}
2216
2217
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002218void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 char buf[BUF_SIZE];
2221 XMLUtil::ToStr( value, buf, BUF_SIZE );
2222 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002223}
2224
Lee Thomason5cae8972012-01-24 18:03:07 -08002225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002227{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002228 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002235}
Lee Thomason751da522012-02-10 08:50:51 -08002236
2237
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002238void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002239{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002240 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002247}
2248
2249
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002250void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002251{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002252 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002259}
2260
2261
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002262bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002263{
Lee Thomason624d43f2012-10-12 10:58:48 -07002264 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 if ( doc.HasBOM() ) {
2266 PushHeader( true, false );
2267 }
2268 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002269}
2270
2271
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002272bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002273{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002274 const XMLElement* parentElem = element.Parent()->ToElement();
2275 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2276 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 while ( attribute ) {
2278 PushAttribute( attribute->Name(), attribute->Value() );
2279 attribute = attribute->Next();
2280 }
2281 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002282}
2283
2284
Uli Kustererca412e82014-02-01 13:35:05 +01002285bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002286{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002287 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002289}
2290
2291
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002292bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 PushText( text.Value(), text.CData() );
2295 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002296}
2297
2298
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002299bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 PushComment( comment.Value() );
2302 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002303}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002305bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 PushDeclaration( declaration.Value() );
2308 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002309}
2310
2311
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002312bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002314 PushUnknown( unknown.Value() );
2315 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002316}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002317
Lee Thomason685b8952012-11-12 13:00:06 -08002318} // namespace tinyxml2
2319