blob: dd8e3fd432ae81128ae51662ceb57ed235135c8d [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.
361 if ( !*(p+3) ) {
362 return 0;
363 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800364
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700365 const char* q = p+3;
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.
396 if ( !*(p+2) ) {
397 return 0;
398 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 const char* q = p+2;
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-Me9fb2b0f2014-09-23 17:27:39 +0400518 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300520 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 return p;
522 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800525 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 static const char* xmlHeader = { "<?" };
527 static const char* commentHeader = { "<!--" };
528 static const char* dtdHeader = { "<!" };
529 static const char* cdataHeader = { "<![CDATA[" };
530 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800531
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 static const int xmlHeaderLen = 2;
533 static const int commentHeaderLen = 4;
534 static const int dtdHeaderLen = 2;
535 static const int cdataHeaderLen = 9;
536 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800537
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
539 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400540 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300542 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += xmlHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300548 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode = new (_commentPool.Alloc()) XMLComment( this );
550 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 p += commentHeaderLen;
552 }
553 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300554 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 p += cdataHeaderLen;
559 text->SetCData( true );
560 }
561 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300562 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700563 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
564 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 p += dtdHeaderLen;
566 }
567 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_elementPool.Alloc()) XMLElement( this );
570 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p += elementHeaderLen;
572 }
573 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300574 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700575 returnNode = new (_textPool.Alloc()) XMLText( this );
576 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 p = start; // Back it up, all the text counts.
578 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 *node = returnNode;
581 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800582}
583
584
Lee Thomason751da522012-02-10 08:50:51 -0800585bool XMLDocument::Accept( XMLVisitor* visitor ) const
586{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300587 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700588 if ( visitor->VisitEnter( *this ) ) {
589 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
590 if ( !node->Accept( visitor ) ) {
591 break;
592 }
593 }
594 }
595 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800596}
Lee Thomason56bdd022012-02-09 18:16:58 -0800597
598
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800599// --------- XMLNode ----------- //
600
601XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 _document( doc ),
603 _parent( 0 ),
604 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200605 _prev( 0 ), _next( 0 ),
606 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800607{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800608}
609
610
611XMLNode::~XMLNode()
612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700614 if ( _parent ) {
615 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800617}
618
Michael Daumling21626882013-10-22 17:03:37 +0200619const char* XMLNode::Value() const
620{
621 return _value.GetStr();
622}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800623
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800624void XMLNode::SetValue( const char* str, bool staticMem )
625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
629 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800632}
633
634
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800635void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800636{
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300638 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700641
Dmitry-Mee3225b12014-09-03 11:03:11 +0400642 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800645}
646
647
648void XMLNode::Unlink( XMLNode* child )
649{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300650 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300651 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child == _firstChild ) {
653 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child == _lastChild ) {
656 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomasond923c672012-01-23 08:44:25 -0800658
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( child->_prev ) {
660 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 if ( child->_next ) {
663 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700665 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800666}
667
668
U-Stream\Leeae25a442012-02-17 17:48:16 -0800669void XMLNode::DeleteChild( XMLNode* node )
670{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300671 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300672 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400674 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800675}
676
677
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
679{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300680 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300681 if ( addThis->_document != _document ) {
682 TIXMLASSERT( false );
683 return 0;
684 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800685 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 if ( _lastChild ) {
688 TIXMLASSERT( _firstChild );
689 TIXMLASSERT( _lastChild->_next == 0 );
690 _lastChild->_next = addThis;
691 addThis->_prev = _lastChild;
692 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
696 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 TIXMLASSERT( _firstChild == 0 );
698 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_prev = 0;
701 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800705}
706
707
Lee Thomason1ff38e02012-02-14 18:18:16 -0800708XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
709{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300710 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300711 if ( addThis->_document != _document ) {
712 TIXMLASSERT( false );
713 return 0;
714 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800715 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 if ( _firstChild ) {
718 TIXMLASSERT( _lastChild );
719 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 _firstChild->_prev = addThis;
722 addThis->_next = _firstChild;
723 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
727 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 TIXMLASSERT( _lastChild == 0 );
729 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_prev = 0;
732 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400735 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800736}
737
738
739XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
740{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 TIXMLASSERT( addThis );
742 if ( addThis->_document != _document ) {
743 TIXMLASSERT( false );
744 return 0;
745 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Dmitry-Meabb2d042014-12-09 12:59:31 +0300747 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700748
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300750 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 return 0;
752 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 // The last node or the only node.
756 return InsertEndChild( addThis );
757 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800758 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 addThis->_prev = afterThis;
760 addThis->_next = afterThis->_next;
761 afterThis->_next->_prev = addThis;
762 afterThis->_next = addThis;
763 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800765}
766
767
768
769
Lee Thomason56bdd022012-02-09 18:16:58 -0800770const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800771{
Lee Thomason624d43f2012-10-12 10:58:48 -0700772 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 XMLElement* element = node->ToElement();
774 if ( element ) {
775 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
776 return element;
777 }
778 }
779 }
780 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800781}
782
783
Lee Thomason56bdd022012-02-09 18:16:58 -0800784const XMLElement* XMLNode::LastChildElement( const char* value ) const
785{
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 XMLElement* element = node->ToElement();
788 if ( element ) {
789 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
790 return element;
791 }
792 }
793 }
794 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800795}
796
797
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800798const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
799{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400800 for( XMLNode* node=this->_next; node; node = node->_next ) {
801 const XMLElement* element = node->ToElement();
802 if ( element
803 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
804 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
806 }
807 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800808}
809
810
811const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
812{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400813 for( XMLNode* node=_prev; node; node = node->_prev ) {
814 const XMLElement* element = node->ToElement();
815 if ( element
816 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
817 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 }
820 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800821}
822
823
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800824char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800825{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 // This is a recursive method, but thinking about it "at the current level"
827 // it is a pretty simple flat list:
828 // <foo/>
829 // <!-- comment -->
830 //
831 // With a special case:
832 // <foo>
833 // </foo>
834 // <!-- comment -->
835 //
836 // Where the closing element (/foo) *must* be the next thing after the opening
837 // element, and the names must match. BUT the tricky bit is that the closing
838 // element will be read by the child.
839 //
840 // 'endTag' is the end tag for this node, it is returned by a call to a child.
841 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800842
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 while( p && *p ) {
844 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800845
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 if ( p == 0 || node == 0 ) {
848 break;
849 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 StrPair endTag;
852 p = node->ParseDeep( p, &endTag );
853 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400854 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 if ( !_document->Error() ) {
856 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 break;
859 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800860
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400861 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500863 // We read the end tag. Return it to the parent.
864 if ( ele->ClosingType() == XMLElement::CLOSING ) {
865 if ( parentEnd ) {
866 ele->_value.TransferTo( parentEnd );
867 }
868 node->_memPool->SetTracked(); // created and then immediately deleted.
869 DeleteNode( node );
870 return p;
871 }
872
873 // Handle an end tag returned to this level.
874 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400875 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300876 if ( endTag.Empty() ) {
877 if ( ele->ClosingType() == XMLElement::OPEN ) {
878 mismatch = true;
879 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300881 else {
882 if ( ele->ClosingType() != XMLElement::OPEN ) {
883 mismatch = true;
884 }
885 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400886 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400889 if ( mismatch ) {
890 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500891 DeleteNode( node );
892 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400893 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
JayXondbfdd8f2014-12-12 20:07:14 -0500895 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
897 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800898}
899
Dmitry-Mee3225b12014-09-03 11:03:11 +0400900void XMLNode::DeleteNode( XMLNode* node )
901{
902 if ( node == 0 ) {
903 return;
904 }
905 MemPool* pool = node->_memPool;
906 node->~XMLNode();
907 pool->Free( node );
908}
909
Lee Thomason3cebdc42015-01-05 17:16:28 -0800910void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300911{
912 TIXMLASSERT( insertThis );
913 TIXMLASSERT( insertThis->_document == _document );
914
915 if ( insertThis->_parent )
916 insertThis->_parent->Unlink( insertThis );
917 else
918 insertThis->_memPool->SetTracked();
919}
920
Lee Thomason5492a1c2012-01-23 15:32:10 -0800921// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800922char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800923{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 const char* start = p;
925 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700926 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 }
930 return p;
931 }
932 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700933 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
934 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 flags |= StrPair::COLLAPSE_WHITESPACE;
936 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700937
Lee Thomason624d43f2012-10-12 10:58:48 -0700938 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 if ( p && *p ) {
940 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300941 }
942 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300943 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 }
946 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800947}
948
949
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800950XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 }
955 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
956 text->SetCData( this->CData() );
957 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958}
959
960
961bool XMLText::ShallowEqual( const XMLNode* compare ) const
962{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400963 const XMLText* text = compare->ToText();
964 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965}
966
967
Lee Thomason56bdd022012-02-09 18:16:58 -0800968bool XMLText::Accept( XMLVisitor* visitor ) const
969{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300970 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800972}
973
974
Lee Thomason3f57d272012-01-11 15:30:03 -0800975// --------- XMLComment ---------- //
976
Lee Thomasone4422302012-01-20 17:59:50 -0800977XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800978{
979}
980
981
Lee Thomasonce0763e2012-01-11 15:43:54 -0800982XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800983{
Lee Thomason3f57d272012-01-11 15:30:03 -0800984}
985
986
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800987char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // Comment parses as text.
990 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800996}
997
998
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 }
1004 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1005 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001006}
1007
1008
1009bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1010{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001011 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001012 const XMLComment* comment = compare->ToComment();
1013 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001014}
1015
1016
Lee Thomason751da522012-02-10 08:50:51 -08001017bool XMLComment::Accept( XMLVisitor* visitor ) const
1018{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001019 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001021}
Lee Thomason56bdd022012-02-09 18:16:58 -08001022
1023
Lee Thomason50f97b22012-02-11 16:33:40 -08001024// --------- XMLDeclaration ---------- //
1025
1026XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1027{
1028}
1029
1030
1031XMLDeclaration::~XMLDeclaration()
1032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001034}
1035
1036
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001037char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 // Declaration parses as text.
1040 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001041 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 }
1045 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001046}
1047
1048
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001049XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1050{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001052 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 }
1054 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1055 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001056}
1057
1058
1059bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1060{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001061 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001062 const XMLDeclaration* declaration = compare->ToDeclaration();
1063 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064}
1065
1066
1067
Lee Thomason50f97b22012-02-11 16:33:40 -08001068bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1069{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001070 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001072}
1073
1074// --------- XMLUnknown ---------- //
1075
1076XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1077{
1078}
1079
1080
1081XMLUnknown::~XMLUnknown()
1082{
1083}
1084
1085
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001086char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 // Unknown parses as text.
1089 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001090
Lee Thomason624d43f2012-10-12 10:58:48 -07001091 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 }
1095 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001096}
1097
1098
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001099XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001102 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 }
1104 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1105 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001106}
1107
1108
1109bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1110{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001111 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001112 const XMLUnknown* unknown = compare->ToUnknown();
1113 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001114}
1115
1116
Lee Thomason50f97b22012-02-11 16:33:40 -08001117bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1118{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001119 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001121}
1122
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001123// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001124
1125const char* XMLAttribute::Name() const
1126{
1127 return _name.GetStr();
1128}
1129
1130const char* XMLAttribute::Value() const
1131{
1132 return _value.GetStr();
1133}
1134
Lee Thomason6f381b72012-03-02 12:59:39 -08001135char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( !p || !*p ) {
1140 return 0;
1141 }
Lee Thomason22aead12012-01-23 13:29:35 -08001142
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 // Skip white space before =
1144 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001145 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 return 0;
1147 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001148
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 ++p; // move up to opening quote
1150 p = XMLUtil::SkipWhiteSpace( p );
1151 if ( *p != '\"' && *p != '\'' ) {
1152 return 0;
1153 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001154
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 char endTag[2] = { *p, 0 };
1156 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001157
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001160}
1161
1162
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001163void XMLAttribute::SetName( const char* n )
1164{
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001166}
1167
1168
Lee Thomason2fa81722012-11-09 12:37:46 -08001169XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 if ( XMLUtil::ToInt( Value(), value )) {
1172 return XML_NO_ERROR;
1173 }
1174 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175}
1176
1177
Lee Thomason2fa81722012-11-09 12:37:46 -08001178XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 if ( XMLUtil::ToUnsigned( Value(), value )) {
1181 return XML_NO_ERROR;
1182 }
1183 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184}
1185
1186
Lee Thomason2fa81722012-11-09 12:37:46 -08001187XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( XMLUtil::ToBool( Value(), value )) {
1190 return XML_NO_ERROR;
1191 }
1192 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001193}
1194
1195
Lee Thomason2fa81722012-11-09 12:37:46 -08001196XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( XMLUtil::ToFloat( Value(), value )) {
1199 return XML_NO_ERROR;
1200 }
1201 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001202}
1203
1204
Lee Thomason2fa81722012-11-09 12:37:46 -08001205XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 if ( XMLUtil::ToDouble( Value(), value )) {
1208 return XML_NO_ERROR;
1209 }
1210 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211}
1212
1213
1214void XMLAttribute::SetAttribute( const char* v )
1215{
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217}
1218
1219
Lee Thomason1ff38e02012-02-14 18:18:16 -08001220void XMLAttribute::SetAttribute( int v )
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 char buf[BUF_SIZE];
1223 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001225}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001226
1227
1228void XMLAttribute::SetAttribute( unsigned v )
1229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 char buf[BUF_SIZE];
1231 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001232 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001233}
1234
1235
1236void XMLAttribute::SetAttribute( bool v )
1237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 char buf[BUF_SIZE];
1239 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241}
1242
1243void XMLAttribute::SetAttribute( double v )
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 char buf[BUF_SIZE];
1246 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
1250void XMLAttribute::SetAttribute( float v )
1251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 char buf[BUF_SIZE];
1253 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001255}
1256
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001257
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001258// --------- XMLElement ---------- //
1259XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 _closingType( 0 ),
1261 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001262{
1263}
1264
1265
1266XMLElement::~XMLElement()
1267{
Lee Thomason624d43f2012-10-12 10:58:48 -07001268 while( _rootAttribute ) {
1269 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001270 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001271 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001273}
1274
1275
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001276const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1277{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001278 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1280 return a;
1281 }
1282 }
1283 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001284}
1285
1286
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001287const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 const XMLAttribute* a = FindAttribute( name );
1290 if ( !a ) {
1291 return 0;
1292 }
1293 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1294 return a->Value();
1295 }
1296 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001297}
1298
1299
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001300const char* XMLElement::GetText() const
1301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001303 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 }
1305 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001306}
1307
1308
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001309void XMLElement::SetText( const char* inText )
1310{
Uli Kusterer869bb592014-01-21 01:36:16 +01001311 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001312 FirstChild()->SetValue( inText );
1313 else {
1314 XMLText* theText = GetDocument()->NewText( inText );
1315 InsertFirstChild( theText );
1316 }
1317}
1318
Lee Thomason5bb2d802014-01-24 10:42:57 -08001319
1320void XMLElement::SetText( int v )
1321{
1322 char buf[BUF_SIZE];
1323 XMLUtil::ToStr( v, buf, BUF_SIZE );
1324 SetText( buf );
1325}
1326
1327
1328void XMLElement::SetText( unsigned v )
1329{
1330 char buf[BUF_SIZE];
1331 XMLUtil::ToStr( v, buf, BUF_SIZE );
1332 SetText( buf );
1333}
1334
1335
1336void XMLElement::SetText( bool v )
1337{
1338 char buf[BUF_SIZE];
1339 XMLUtil::ToStr( v, buf, BUF_SIZE );
1340 SetText( buf );
1341}
1342
1343
1344void XMLElement::SetText( float v )
1345{
1346 char buf[BUF_SIZE];
1347 XMLUtil::ToStr( v, buf, BUF_SIZE );
1348 SetText( buf );
1349}
1350
1351
1352void XMLElement::SetText( double v )
1353{
1354 char buf[BUF_SIZE];
1355 XMLUtil::ToStr( v, buf, BUF_SIZE );
1356 SetText( buf );
1357}
1358
1359
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001363 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001364 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 return XML_SUCCESS;
1366 }
1367 return XML_CAN_NOT_CONVERT_TEXT;
1368 }
1369 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001370}
1371
1372
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001376 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001377 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 return XML_SUCCESS;
1379 }
1380 return XML_CAN_NOT_CONVERT_TEXT;
1381 }
1382 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001383}
1384
1385
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001389 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 return XML_SUCCESS;
1392 }
1393 return XML_CAN_NOT_CONVERT_TEXT;
1394 }
1395 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001396}
1397
1398
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001402 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 return XML_SUCCESS;
1405 }
1406 return XML_CAN_NOT_CONVERT_TEXT;
1407 }
1408 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001409}
1410
1411
MortenMacFly4ee49f12013-01-14 20:03:14 +01001412XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001415 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001416 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 return XML_SUCCESS;
1418 }
1419 return XML_CAN_NOT_CONVERT_TEXT;
1420 }
1421 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
1425
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001426XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 XMLAttribute* last = 0;
1429 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1434 break;
1435 }
1436 }
1437 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001438 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1440 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 }
1444 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 }
1447 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001448 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 }
1450 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001451}
1452
1453
U-Stream\Leeae25a442012-02-17 17:48:16 -08001454void XMLElement::DeleteAttribute( const char* name )
1455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1459 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001465 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 break;
1467 }
1468 prev = a;
1469 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001470}
1471
1472
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001473char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 const char* start = p;
1476 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001477
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 // Read the attributes.
1479 while( p ) {
1480 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001481 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 return 0;
1484 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001485
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001487 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001488 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1490 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001491 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001492
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001495 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 return 0;
1498 }
1499 // There is a minor bug here: if the attribute in the source xml
1500 // document is duplicated, it will not be detected and the
1501 // attribute will be doubly added. However, tracking the 'prevAttribute'
1502 // avoids re-scanning the attribute list. Preferring performance for
1503 // now, may reconsider in the future.
1504 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 }
1507 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 }
1510 prevAttribute = attrib;
1511 }
1512 // end of the tag
1513 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 return p+2; // done; sealed element.
1516 }
1517 // end of the tag
1518 else if ( *p == '>' ) {
1519 ++p;
1520 break;
1521 }
1522 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 return 0;
1525 }
1526 }
1527 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001528}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Dmitry-Mee3225b12014-09-03 11:03:11 +04001530void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1531{
1532 if ( attribute == 0 ) {
1533 return;
1534 }
1535 MemPool* pool = attribute->_memPool;
1536 attribute->~XMLAttribute();
1537 pool->Free( attribute );
1538}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001539
Lee Thomason67d61312012-01-24 16:01:51 -08001540//
1541// <ele></ele>
1542// <ele>foo<b>bar</b></ele>
1543//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001544char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 // Read the element name.
1547 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 // The closing element is the </element> form. It is
1550 // parsed just like a regular element then deleted from
1551 // the DOM.
1552 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 ++p;
1555 }
Lee Thomason67d61312012-01-24 16:01:51 -08001556
Lee Thomason624d43f2012-10-12 10:58:48 -07001557 p = _value.ParseName( p );
1558 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 return 0;
1560 }
Lee Thomason67d61312012-01-24 16:01:51 -08001561
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001563 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 return p;
1565 }
Lee Thomason67d61312012-01-24 16:01:51 -08001566
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 p = XMLNode::ParseDeep( p, strPair );
1568 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001569}
1570
1571
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572
1573XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001576 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 }
1578 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1579 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1580 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1581 }
1582 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001583}
1584
1585
1586bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1587{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001588 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 const XMLElement* other = compare->ToElement();
1590 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 const XMLAttribute* a=FirstAttribute();
1593 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001594
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 while ( a && b ) {
1596 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1597 return false;
1598 }
1599 a = a->Next();
1600 b = b->Next();
1601 }
1602 if ( a || b ) {
1603 // different count
1604 return false;
1605 }
1606 return true;
1607 }
1608 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001609}
1610
1611
Lee Thomason751da522012-02-10 08:50:51 -08001612bool XMLElement::Accept( XMLVisitor* visitor ) const
1613{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001614 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1617 if ( !node->Accept( visitor ) ) {
1618 break;
1619 }
1620 }
1621 }
1622 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001623}
Lee Thomason56bdd022012-02-09 18:16:58 -08001624
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001625
Lee Thomason3f57d272012-01-11 15:30:03 -08001626// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001627
1628// Warning: List must match 'enum XMLError'
1629const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1630 "XML_SUCCESS",
1631 "XML_NO_ATTRIBUTE",
1632 "XML_WRONG_ATTRIBUTE_TYPE",
1633 "XML_ERROR_FILE_NOT_FOUND",
1634 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1635 "XML_ERROR_FILE_READ_ERROR",
1636 "XML_ERROR_ELEMENT_MISMATCH",
1637 "XML_ERROR_PARSING_ELEMENT",
1638 "XML_ERROR_PARSING_ATTRIBUTE",
1639 "XML_ERROR_IDENTIFYING_TAG",
1640 "XML_ERROR_PARSING_TEXT",
1641 "XML_ERROR_PARSING_CDATA",
1642 "XML_ERROR_PARSING_COMMENT",
1643 "XML_ERROR_PARSING_DECLARATION",
1644 "XML_ERROR_PARSING_UNKNOWN",
1645 "XML_ERROR_EMPTY_DOCUMENT",
1646 "XML_ERROR_MISMATCHED_ELEMENT",
1647 "XML_ERROR_PARSING",
1648 "XML_CAN_NOT_CONVERT_TEXT",
1649 "XML_NO_TEXT_NODE"
1650};
1651
1652
Lee Thomason624d43f2012-10-12 10:58:48 -07001653XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 _writeBOM( false ),
1656 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001657 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 _whitespace( whitespace ),
1659 _errorStr1( 0 ),
1660 _errorStr2( 0 ),
1661 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001662{
Lee Thomason624d43f2012-10-12 10:58:48 -07001663 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001664}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001665
1666
Lee Thomason3f57d272012-01-11 15:30:03 -08001667XMLDocument::~XMLDocument()
1668{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001669 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001670}
1671
1672
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001673void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001674{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001675 DeleteChildren();
1676
Dmitry-Meab37df82014-11-28 12:08:36 +03001677#ifdef DEBUG
1678 const bool hadError = Error();
1679#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 _errorID = XML_NO_ERROR;
1681 _errorStr1 = 0;
1682 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001683
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 delete [] _charBuffer;
1685 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001686
1687#if 0
1688 _textPool.Trace( "text" );
1689 _elementPool.Trace( "element" );
1690 _commentPool.Trace( "comment" );
1691 _attributePool.Trace( "attribute" );
1692#endif
1693
1694#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001695 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001696 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1697 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1698 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1699 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1700 }
1701#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001702}
1703
Lee Thomason3f57d272012-01-11 15:30:03 -08001704
Lee Thomason2c85a712012-01-31 08:24:24 -08001705XMLElement* XMLDocument::NewElement( const char* name )
1706{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001707 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1709 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 ele->SetName( name );
1711 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001712}
1713
1714
Lee Thomason1ff38e02012-02-14 18:18:16 -08001715XMLComment* XMLDocument::NewComment( const char* str )
1716{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001717 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1719 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 comment->SetValue( str );
1721 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001722}
1723
1724
1725XMLText* XMLDocument::NewText( const char* str )
1726{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001727 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1729 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 text->SetValue( str );
1731 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001732}
1733
1734
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001735XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1736{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001737 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1739 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1741 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001742}
1743
1744
1745XMLUnknown* XMLDocument::NewUnknown( const char* str )
1746{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001747 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1749 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 unk->SetValue( str );
1751 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001752}
1753
Dmitry-Me01578db2014-08-19 10:18:48 +04001754static FILE* callfopen( const char* filepath, const char* mode )
1755{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001756 TIXMLASSERT( filepath );
1757 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001758#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1759 FILE* fp = 0;
1760 errno_t err = fopen_s( &fp, filepath, mode );
1761 if ( err ) {
1762 return 0;
1763 }
1764#else
1765 FILE* fp = fopen( filepath, mode );
1766#endif
1767 return fp;
1768}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001769
1770void XMLDocument::DeleteNode( XMLNode* node ) {
1771 TIXMLASSERT( node );
1772 TIXMLASSERT(node->_document == this );
1773 if (node->_parent) {
1774 node->_parent->DeleteChild( node );
1775 }
1776 else {
1777 // Isn't in the tree.
1778 // Use the parent delete.
1779 // Also, we need to mark it tracked: we 'know'
1780 // it was never used.
1781 node->_memPool->SetTracked();
1782 // Call the static XMLNode version:
1783 XMLNode::DeleteNode(node);
1784 }
1785}
1786
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001787
Lee Thomason2fa81722012-11-09 12:37:46 -08001788XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001789{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001790 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001791 FILE* fp = callfopen( filename, "rb" );
1792 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 }
1796 LoadFile( fp );
1797 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001799}
1800
1801
Lee Thomason2fa81722012-11-09 12:37:46 -08001802XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001803{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001804 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001805
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001806 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001807 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001808 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1809 return _errorID;
1810 }
1811
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001813 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001815 if ( filelength == -1L ) {
1816 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1817 return _errorID;
1818 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001819
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001820 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001822 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001825
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 _charBuffer = new char[size+1];
1827 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 if ( read != size ) {
1829 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001832
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834
Dmitry-Me97476b72015-01-01 16:15:57 +03001835 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837}
1838
1839
Lee Thomason2fa81722012-11-09 12:37:46 -08001840XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001841{
Dmitry-Me01578db2014-08-19 10:18:48 +04001842 FILE* fp = callfopen( filename, "w" );
1843 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 }
1847 SaveFile(fp, compact);
1848 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001850}
1851
1852
Lee Thomason2fa81722012-11-09 12:37:46 -08001853XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001854{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 XMLPrinter stream( fp, compact );
1856 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001858}
1859
Lee Thomason1ff38e02012-02-14 18:18:16 -08001860
Lee Thomason2fa81722012-11-09 12:37:46 -08001861XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001862{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001863 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001864
Lee Thomason82d32002014-02-21 22:47:18 -08001865 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 }
1869 if ( len == (size_t)(-1) ) {
1870 len = strlen( p );
1871 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _charBuffer = new char[ len+1 ];
1873 memcpy( _charBuffer, p, len );
1874 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001875
Dmitry-Me97476b72015-01-01 16:15:57 +03001876 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001877 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001878 // clean up now essentially dangling memory.
1879 // and the parse fail can put objects in the
1880 // pools that are dead and inaccessible.
1881 DeleteChildren();
1882 _elementPool.Clear();
1883 _attributePool.Clear();
1884 _textPool.Clear();
1885 _commentPool.Clear();
1886 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001888}
1889
1890
PKEuS1c5f99e2013-07-06 11:28:39 +02001891void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001892{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 XMLPrinter stdStreamer( stdout );
1894 if ( !streamer ) {
1895 streamer = &stdStreamer;
1896 }
1897 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001898}
1899
1900
Lee Thomason2fa81722012-11-09 12:37:46 -08001901void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001902{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001903 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 _errorID = error;
1905 _errorStr1 = str1;
1906 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001907}
1908
Lee Thomason331596e2014-09-11 14:56:43 -07001909const char* XMLDocument::ErrorName() const
1910{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001911 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001912 return _errorNames[_errorID];
1913}
Lee Thomason5cae8972012-01-24 18:03:07 -08001914
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001915void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001916{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001917 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 static const int LEN = 20;
1919 char buf1[LEN] = { 0 };
1920 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001921
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 if ( _errorStr1 ) {
1923 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 if ( _errorStr2 ) {
1926 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001928
Lee Thomason331596e2014-09-11 14:56:43 -07001929 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1930 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001932}
1933
Dmitry-Me97476b72015-01-01 16:15:57 +03001934void XMLDocument::Parse()
1935{
1936 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1937 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001938 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001939 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001940 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001941 if ( !*p ) {
1942 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1943 return;
1944 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001945 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001946}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001947
PKEuS1bfb9542013-08-04 13:51:17 +02001948XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _elementJustOpened( false ),
1950 _firstElement( true ),
1951 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001952 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 _textDepth( -1 ),
1954 _processEntities( true ),
1955 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001956{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001958 _entityFlag[i] = false;
1959 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 }
1961 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001962 const char entityValue = entities[i].value;
1963 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1964 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001966 _restrictedEntityFlag[(unsigned char)'&'] = true;
1967 _restrictedEntityFlag[(unsigned char)'<'] = true;
1968 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001970}
1971
1972
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001973void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001974{
1975 va_list va;
1976 va_start( va, format );
1977
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 if ( _fp ) {
1979 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 }
1981 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001982#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001983 #if defined(WINCE)
1984 int len = 512;
1985 do {
1986 len = len*2;
1987 char* str = new char[len]();
1988 len = _vsnprintf(str, len, format, va);
1989 delete[] str;
1990 }while (len < 0);
1991 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001992 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001993 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994#else
1995 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001996#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 // Close out and re-start the va-args
1998 va_end( va );
1999 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07002000 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2001#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002002 #if defined(WINCE)
2003 _vsnprintf( p, len+1, format, va );
2004 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002005 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002006 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002007#else
2008 vsnprintf( p, len+1, format, va );
2009#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002011 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002012}
2013
2014
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002015void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 for( int i=0; i<depth; ++i ) {
2018 Print( " " );
2019 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002020}
2021
2022
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002023void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 // Look for runs of bytes between entities to print.
2026 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002028
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 while ( *q ) {
2031 // Remember, char is sometimes signed. (How many times has that bitten me?)
2032 if ( *q > 0 && *q < ENTITY_RANGE ) {
2033 // Check for entities. If one is found, flush
2034 // the stream up until the entity, write the
2035 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002036 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 while ( p < q ) {
2038 Print( "%c", *p );
2039 ++p;
2040 }
2041 for( int i=0; i<NUM_ENTITIES; ++i ) {
2042 if ( entities[i].value == *q ) {
2043 Print( "&%s;", entities[i].pattern );
2044 break;
2045 }
2046 }
2047 ++p;
2048 }
2049 }
2050 ++q;
2051 }
2052 }
2053 // Flush the remaining string. This will be the entire
2054 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 Print( "%s", p );
2057 }
Lee Thomason857b8682012-01-25 17:50:25 -08002058}
2059
U-Stream\Leeae25a442012-02-17 17:48:16 -08002060
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002061void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002064 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 -07002065 Print( "%s", bom );
2066 }
2067 if ( writeDec ) {
2068 PushDeclaration( "xml version=\"1.0\"" );
2069 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002070}
2071
2072
Uli Kusterer593a33d2014-02-01 12:48:51 +01002073void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002074{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002075 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002077
Uli Kusterer593a33d2014-02-01 12:48:51 +01002078 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002080 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002081 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002084
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 _elementJustOpened = true;
2087 _firstElement = false;
2088 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002089}
2090
2091
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002092void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002093{
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 Print( " %s=\"", name );
2096 PrintString( value, false );
2097 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002098}
2099
2100
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002101void XMLPrinter::PushAttribute( const char* name, int v )
2102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 char buf[BUF_SIZE];
2104 XMLUtil::ToStr( v, buf, BUF_SIZE );
2105 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002106}
2107
2108
2109void XMLPrinter::PushAttribute( const char* name, unsigned v )
2110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 char buf[BUF_SIZE];
2112 XMLUtil::ToStr( v, buf, BUF_SIZE );
2113 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
2116
2117void XMLPrinter::PushAttribute( const char* name, bool v )
2118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( v, buf, BUF_SIZE );
2121 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
2124
2125void XMLPrinter::PushAttribute( const char* name, double v )
2126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 char buf[BUF_SIZE];
2128 XMLUtil::ToStr( v, buf, BUF_SIZE );
2129 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002130}
2131
2132
Uli Kustererca412e82014-02-01 13:35:05 +01002133void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002134{
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 --_depth;
2136 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002137
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 Print( "/>" );
2140 }
2141 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002142 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 }
2146 Print( "</%s>", name );
2147 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002148
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 if ( _textDepth == _depth ) {
2150 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 }
Uli Kustererca412e82014-02-01 13:35:05 +01002152 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 Print( "\n" );
2154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002156}
2157
2158
Dmitry-Mea092bc12014-12-23 17:57:05 +03002159void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002160{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002161 if ( !_elementJustOpened ) {
2162 return;
2163 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002166}
2167
2168
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002169void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002170{
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002172
Dmitry-Mea092bc12014-12-23 17:57:05 +03002173 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 if ( cdata ) {
2175 Print( "<![CDATA[" );
2176 Print( "%s", text );
2177 Print( "]]>" );
2178 }
2179 else {
2180 PrintString( text, true );
2181 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002182}
2183
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002184void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 char buf[BUF_SIZE];
2187 XMLUtil::ToStr( value, buf, BUF_SIZE );
2188 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002189}
2190
2191
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002192void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 char buf[BUF_SIZE];
2195 XMLUtil::ToStr( value, buf, BUF_SIZE );
2196 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002197}
2198
2199
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002200void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 char buf[BUF_SIZE];
2203 XMLUtil::ToStr( value, buf, BUF_SIZE );
2204 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002205}
2206
2207
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002208void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 char buf[BUF_SIZE];
2211 XMLUtil::ToStr( value, buf, BUF_SIZE );
2212 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002213}
2214
2215
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002216void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 char buf[BUF_SIZE];
2219 XMLUtil::ToStr( value, buf, BUF_SIZE );
2220 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002221}
2222
Lee Thomason5cae8972012-01-24 18:03:07 -08002223
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002224void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002225{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002226 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002233}
Lee Thomason751da522012-02-10 08:50:51 -08002234
2235
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002236void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002238 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002245}
2246
2247
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002248void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002249{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002250 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002257}
2258
2259
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002260bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002261{
Lee Thomason624d43f2012-10-12 10:58:48 -07002262 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 if ( doc.HasBOM() ) {
2264 PushHeader( true, false );
2265 }
2266 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002267}
2268
2269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002271{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002272 const XMLElement* parentElem = element.Parent()->ToElement();
2273 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2274 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 while ( attribute ) {
2276 PushAttribute( attribute->Name(), attribute->Value() );
2277 attribute = attribute->Next();
2278 }
2279 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002280}
2281
2282
Uli Kustererca412e82014-02-01 13:35:05 +01002283bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002284{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002285 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002287}
2288
2289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 PushText( text.Value(), text.CData() );
2293 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002294}
2295
2296
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002297bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 PushComment( comment.Value() );
2300 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002301}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002303bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 PushDeclaration( declaration.Value() );
2306 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002307}
2308
2309
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002310bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 PushUnknown( unknown.Value() );
2313 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002314}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002315
Lee Thomason685b8952012-11-12 13:00:06 -08002316} // namespace tinyxml2
2317