blob: a9948cf2d237b73b371b9d2e646265aa65a6a509 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300354 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 ptrdiff_t delta = 0;
356 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800357 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 if ( *(p+2) == 'x' ) {
360 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300361 const char* q = p+3;
362 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Dmitry-Me9f56e122015-01-12 10:07:54 +0300368 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 return 0;
370 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800371 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != 'x' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else if ( *q >= 'a' && *q <= 'f' ) {
381 ucs += mult * (*q - 'a' + 10);
382 }
383 else if ( *q >= 'A' && *q <= 'F' ) {
384 ucs += mult * (*q - 'A' + 10 );
385 }
386 else {
387 return 0;
388 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300389 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 mult *= 16;
391 --q;
392 }
393 }
394 else {
395 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300396 const char* q = p+2;
397 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return 0;
399 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Lee Thomason7e67bc82015-01-12 14:05:12 -0800401 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Dmitry-Me9f56e122015-01-12 10:07:54 +0300403 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return 0;
405 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800406 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 delta = q-p;
409 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 while ( *q != '#' ) {
412 if ( *q >= '0' && *q <= '9' ) {
413 ucs += mult * (*q - '0');
414 }
415 else {
416 return 0;
417 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300418 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 mult *= 10;
420 --q;
421 }
422 }
423 // convert the UCS to UTF-8
424 ConvertUTF32ToUTF8( ucs, value, length );
425 return p + delta + 1;
426 }
427 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800429
430
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700431void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
442
443void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448/*
449 ToStr() of a number is a very tricky topic.
450 https://github.com/leethomason/tinyxml2/issues/106
451*/
Lee Thomason21be8822012-07-15 17:27:22 -0700452void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
459{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800460 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464bool XMLUtil::ToInt( const char* str, int* value )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700474 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
475 return true;
476 }
477 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700478}
479
480bool XMLUtil::ToBool( const char* str, bool* value )
481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 int ival = 0;
483 if ( ToInt( str, &ival )) {
484 *value = (ival==0) ? false : true;
485 return true;
486 }
487 if ( StringEqual( str, "true" ) ) {
488 *value = true;
489 return true;
490 }
491 else if ( StringEqual( str, "false" ) ) {
492 *value = false;
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498
499bool XMLUtil::ToFloat( const char* str, float* value )
500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
502 return true;
503 }
504 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700505}
506
507bool XMLUtil::ToDouble( const char* str, double* value )
508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
510 return true;
511 }
512 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700513}
514
515
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700516char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517{
Dmitry-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 );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002000 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002001 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2002#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002003 #if defined(WINCE)
2004 _vsnprintf( p, len+1, format, va );
2005 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002006 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002007 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002008#else
2009 vsnprintf( p, len+1, format, va );
2010#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002012 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 for( int i=0; i<depth; ++i ) {
2019 Print( " " );
2020 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002021}
2022
2023
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002024void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 // Look for runs of bytes between entities to print.
2027 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002028
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002030 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 while ( *q ) {
2032 // Remember, char is sometimes signed. (How many times has that bitten me?)
2033 if ( *q > 0 && *q < ENTITY_RANGE ) {
2034 // Check for entities. If one is found, flush
2035 // the stream up until the entity, write the
2036 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002037 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 while ( p < q ) {
2039 Print( "%c", *p );
2040 ++p;
2041 }
2042 for( int i=0; i<NUM_ENTITIES; ++i ) {
2043 if ( entities[i].value == *q ) {
2044 Print( "&%s;", entities[i].pattern );
2045 break;
2046 }
2047 }
2048 ++p;
2049 }
2050 }
2051 ++q;
2052 }
2053 }
2054 // Flush the remaining string. This will be the entire
2055 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 Print( "%s", p );
2058 }
Lee Thomason857b8682012-01-25 17:50:25 -08002059}
2060
U-Stream\Leeae25a442012-02-17 17:48:16 -08002061
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002062void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002063{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002065 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 -07002066 Print( "%s", bom );
2067 }
2068 if ( writeDec ) {
2069 PushDeclaration( "xml version=\"1.0\"" );
2070 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002071}
2072
2073
Uli Kusterer593a33d2014-02-01 12:48:51 +01002074void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002075{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002076 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002078
Uli Kusterer593a33d2014-02-01 12:48:51 +01002079 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002081 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002082 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 _elementJustOpened = true;
2088 _firstElement = false;
2089 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002090}
2091
2092
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002093void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002094{
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 Print( " %s=\"", name );
2097 PrintString( value, false );
2098 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002099}
2100
2101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102void XMLPrinter::PushAttribute( const char* name, int v )
2103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 char buf[BUF_SIZE];
2105 XMLUtil::ToStr( v, buf, BUF_SIZE );
2106 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
2109
2110void XMLPrinter::PushAttribute( const char* name, unsigned v )
2111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 char buf[BUF_SIZE];
2113 XMLUtil::ToStr( v, buf, BUF_SIZE );
2114 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
2117
2118void XMLPrinter::PushAttribute( const char* name, bool v )
2119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 char buf[BUF_SIZE];
2121 XMLUtil::ToStr( v, buf, BUF_SIZE );
2122 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002123}
2124
2125
2126void XMLPrinter::PushAttribute( const char* name, double v )
2127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 char buf[BUF_SIZE];
2129 XMLUtil::ToStr( v, buf, BUF_SIZE );
2130 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002131}
2132
2133
Uli Kustererca412e82014-02-01 13:35:05 +01002134void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002135{
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 --_depth;
2137 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002138
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 Print( "/>" );
2141 }
2142 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002143 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
2147 Print( "</%s>", name );
2148 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002149
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 if ( _textDepth == _depth ) {
2151 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 }
Uli Kustererca412e82014-02-01 13:35:05 +01002153 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 Print( "\n" );
2155 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002157}
2158
2159
Dmitry-Mea092bc12014-12-23 17:57:05 +03002160void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002161{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002162 if ( !_elementJustOpened ) {
2163 return;
2164 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002167}
2168
2169
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002170void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002171{
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002173
Dmitry-Mea092bc12014-12-23 17:57:05 +03002174 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 if ( cdata ) {
2176 Print( "<![CDATA[" );
2177 Print( "%s", text );
2178 Print( "]]>" );
2179 }
2180 else {
2181 PrintString( text, true );
2182 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002183}
2184
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002185void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 char buf[BUF_SIZE];
2188 XMLUtil::ToStr( value, buf, BUF_SIZE );
2189 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002190}
2191
2192
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002193void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 char buf[BUF_SIZE];
2196 XMLUtil::ToStr( value, buf, BUF_SIZE );
2197 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002198}
2199
2200
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002201void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 char buf[BUF_SIZE];
2204 XMLUtil::ToStr( value, buf, BUF_SIZE );
2205 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002206}
2207
2208
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002209void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 char buf[BUF_SIZE];
2212 XMLUtil::ToStr( value, buf, BUF_SIZE );
2213 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002214}
2215
2216
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002217void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 char buf[BUF_SIZE];
2220 XMLUtil::ToStr( value, buf, BUF_SIZE );
2221 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002222}
2223
Lee Thomason5cae8972012-01-24 18:03:07 -08002224
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002225void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002226{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002227 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002234}
Lee Thomason751da522012-02-10 08:50:51 -08002235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002239 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246}
2247
2248
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002249void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002250{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002251 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002258}
2259
2260
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002261bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002262{
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 if ( doc.HasBOM() ) {
2265 PushHeader( true, false );
2266 }
2267 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002268}
2269
2270
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002271bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002272{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002273 const XMLElement* parentElem = element.Parent()->ToElement();
2274 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2275 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 while ( attribute ) {
2277 PushAttribute( attribute->Name(), attribute->Value() );
2278 attribute = attribute->Next();
2279 }
2280 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002281}
2282
2283
Uli Kustererca412e82014-02-01 13:35:05 +01002284bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002285{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002286 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002288}
2289
2290
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002291bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002292{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 PushText( text.Value(), text.CData() );
2294 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002295}
2296
2297
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002298bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 PushComment( comment.Value() );
2301 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002302}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002304bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 PushDeclaration( declaration.Value() );
2307 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002308}
2309
2310
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002311bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 PushUnknown( unknown.Value() );
2314 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002315}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002316
Lee Thomason685b8952012-11-12 13:00:06 -08002317} // namespace tinyxml2
2318