blob: ef00f1380e74d7b0ec61946139397e8f91d06f76 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300354 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 ptrdiff_t delta = 0;
356 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800357 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 if ( *(p+2) == 'x' ) {
360 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300361 const char* q = p+3;
362 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Dmitry-Me9f56e122015-01-12 10:07:54 +0300368 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 return 0;
370 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800371 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != 'x' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else if ( *q >= 'a' && *q <= 'f' ) {
381 ucs += mult * (*q - 'a' + 10);
382 }
383 else if ( *q >= 'A' && *q <= 'F' ) {
384 ucs += mult * (*q - 'A' + 10 );
385 }
386 else {
387 return 0;
388 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300389 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 mult *= 16;
391 --q;
392 }
393 }
394 else {
395 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300396 const char* q = p+2;
397 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return 0;
399 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800400
Lee Thomason7e67bc82015-01-12 14:05:12 -0800401 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Dmitry-Me9f56e122015-01-12 10:07:54 +0300403 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return 0;
405 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800406 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 delta = q-p;
409 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 while ( *q != '#' ) {
412 if ( *q >= '0' && *q <= '9' ) {
413 ucs += mult * (*q - '0');
414 }
415 else {
416 return 0;
417 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300418 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 mult *= 10;
420 --q;
421 }
422 }
423 // convert the UCS to UTF-8
424 ConvertUTF32ToUTF8( ucs, value, length );
425 return p + delta + 1;
426 }
427 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800429
430
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700431void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
442
443void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448/*
449 ToStr() of a number is a very tricky topic.
450 https://github.com/leethomason/tinyxml2/issues/106
451*/
Lee Thomason21be8822012-07-15 17:27:22 -0700452void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
453{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800454 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
459{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800460 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464bool XMLUtil::ToInt( const char* str, int* value )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700474 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
475 return true;
476 }
477 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700478}
479
480bool XMLUtil::ToBool( const char* str, bool* value )
481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 int ival = 0;
483 if ( ToInt( str, &ival )) {
484 *value = (ival==0) ? false : true;
485 return true;
486 }
487 if ( StringEqual( str, "true" ) ) {
488 *value = true;
489 return true;
490 }
491 else if ( StringEqual( str, "false" ) ) {
492 *value = false;
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498
499bool XMLUtil::ToFloat( const char* str, float* value )
500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
502 return true;
503 }
504 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700505}
506
507bool XMLUtil::ToDouble( const char* str, double* value )
508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
510 return true;
511 }
512 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700513}
514
515
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700516char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517{
Dmitry-Me02384662015-03-03 16:02:13 +0300518 TIXMLASSERT( node );
519 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400520 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300522 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300523 *node = 0;
524 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 return p;
526 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800527
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800529 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 static const char* xmlHeader = { "<?" };
531 static const char* commentHeader = { "<!--" };
532 static const char* dtdHeader = { "<!" };
533 static const char* cdataHeader = { "<![CDATA[" };
534 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800535
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 static const int xmlHeaderLen = 2;
537 static const int commentHeaderLen = 4;
538 static const int dtdHeaderLen = 2;
539 static const int cdataHeaderLen = 9;
540 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800541
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
543 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400544 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300546 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
548 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 p += xmlHeaderLen;
550 }
551 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300552 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 returnNode = new (_commentPool.Alloc()) XMLComment( this );
554 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p += commentHeaderLen;
556 }
557 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300558 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700561 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p += cdataHeaderLen;
563 text->SetCData( true );
564 }
565 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300566 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
568 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 p += dtdHeaderLen;
570 }
571 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300572 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700573 returnNode = new (_elementPool.Alloc()) XMLElement( this );
574 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 p += elementHeaderLen;
576 }
577 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300578 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700579 returnNode = new (_textPool.Alloc()) XMLText( this );
580 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 p = start; // Back it up, all the text counts.
582 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800583
Dmitry-Me02384662015-03-03 16:02:13 +0300584 TIXMLASSERT( returnNode );
585 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700586 *node = returnNode;
587 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588}
589
590
Lee Thomason751da522012-02-10 08:50:51 -0800591bool XMLDocument::Accept( XMLVisitor* visitor ) const
592{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300593 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( visitor->VisitEnter( *this ) ) {
595 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
596 if ( !node->Accept( visitor ) ) {
597 break;
598 }
599 }
600 }
601 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800602}
Lee Thomason56bdd022012-02-09 18:16:58 -0800603
604
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605// --------- XMLNode ----------- //
606
607XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 _document( doc ),
609 _parent( 0 ),
610 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200611 _prev( 0 ), _next( 0 ),
612 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800613{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800614}
615
616
617XMLNode::~XMLNode()
618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( _parent ) {
621 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800623}
624
Michael Daumling21626882013-10-22 17:03:37 +0200625const char* XMLNode::Value() const
626{
627 return _value.GetStr();
628}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800629
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800630void XMLNode::SetValue( const char* str, bool staticMem )
631{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
635 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800638}
639
640
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800641void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800642{
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700647
Dmitry-Mee3225b12014-09-03 11:03:11 +0400648 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800651}
652
653
654void XMLNode::Unlink( XMLNode* child )
655{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300656 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300657 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 if ( child == _firstChild ) {
659 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 if ( child == _lastChild ) {
662 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 }
Lee Thomasond923c672012-01-23 08:44:25 -0800664
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 if ( child->_prev ) {
666 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 if ( child->_next ) {
669 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700671 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800672}
673
674
U-Stream\Leeae25a442012-02-17 17:48:16 -0800675void XMLNode::DeleteChild( XMLNode* node )
676{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300677 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300678 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400680 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800681}
682
683
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800684XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
685{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300686 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300687 if ( addThis->_document != _document ) {
688 TIXMLASSERT( false );
689 return 0;
690 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800691 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 if ( _lastChild ) {
694 TIXMLASSERT( _firstChild );
695 TIXMLASSERT( _lastChild->_next == 0 );
696 _lastChild->_next = addThis;
697 addThis->_prev = _lastChild;
698 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 }
702 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 TIXMLASSERT( _firstChild == 0 );
704 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 addThis->_prev = 0;
707 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800711}
712
713
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
715{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300716 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300717 if ( addThis->_document != _document ) {
718 TIXMLASSERT( false );
719 return 0;
720 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800721 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 if ( _firstChild ) {
724 TIXMLASSERT( _lastChild );
725 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800726
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 _firstChild->_prev = addThis;
728 addThis->_next = _firstChild;
729 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 }
733 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 TIXMLASSERT( _lastChild == 0 );
735 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800736
Lee Thomason624d43f2012-10-12 10:58:48 -0700737 addThis->_prev = 0;
738 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400741 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800742}
743
744
745XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
746{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300747 TIXMLASSERT( addThis );
748 if ( addThis->_document != _document ) {
749 TIXMLASSERT( false );
750 return 0;
751 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700752
Dmitry-Meabb2d042014-12-09 12:59:31 +0300753 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700754
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300756 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 return 0;
758 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800759
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 // The last node or the only node.
762 return InsertEndChild( addThis );
763 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800764 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 addThis->_prev = afterThis;
766 addThis->_next = afterThis->_next;
767 afterThis->_next->_prev = addThis;
768 afterThis->_next = addThis;
769 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800771}
772
773
774
775
Lee Thomason56bdd022012-02-09 18:16:58 -0800776const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800777{
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 XMLElement* element = node->ToElement();
780 if ( element ) {
781 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
782 return element;
783 }
784 }
785 }
786 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800787}
788
789
Lee Thomason56bdd022012-02-09 18:16:58 -0800790const XMLElement* XMLNode::LastChildElement( const char* value ) const
791{
Lee Thomason624d43f2012-10-12 10:58:48 -0700792 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 XMLElement* element = node->ToElement();
794 if ( element ) {
795 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
796 return element;
797 }
798 }
799 }
800 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800801}
802
803
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800804const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
805{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400806 for( XMLNode* node=this->_next; node; node = node->_next ) {
807 const XMLElement* element = node->ToElement();
808 if ( element
809 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
810 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
812 }
813 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800814}
815
816
817const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
818{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400819 for( XMLNode* node=_prev; node; node = node->_prev ) {
820 const XMLElement* element = node->ToElement();
821 if ( element
822 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
823 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 }
825 }
826 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800827}
828
829
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800830char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800831{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 // This is a recursive method, but thinking about it "at the current level"
833 // it is a pretty simple flat list:
834 // <foo/>
835 // <!-- comment -->
836 //
837 // With a special case:
838 // <foo>
839 // </foo>
840 // <!-- comment -->
841 //
842 // Where the closing element (/foo) *must* be the next thing after the opening
843 // element, and the names must match. BUT the tricky bit is that the closing
844 // element will be read by the child.
845 //
846 // 'endTag' is the end tag for this node, it is returned by a call to a child.
847 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800848
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 while( p && *p ) {
850 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300853 if ( node == 0 ) {
854 break;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 StrPair endTag;
858 p = node->ParseDeep( p, &endTag );
859 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400860 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 if ( !_document->Error() ) {
862 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
864 break;
865 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800866
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400867 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500869 // We read the end tag. Return it to the parent.
870 if ( ele->ClosingType() == XMLElement::CLOSING ) {
871 if ( parentEnd ) {
872 ele->_value.TransferTo( parentEnd );
873 }
874 node->_memPool->SetTracked(); // created and then immediately deleted.
875 DeleteNode( node );
876 return p;
877 }
878
879 // Handle an end tag returned to this level.
880 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300882 if ( endTag.Empty() ) {
883 if ( ele->ClosingType() == XMLElement::OPEN ) {
884 mismatch = true;
885 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300887 else {
888 if ( ele->ClosingType() != XMLElement::OPEN ) {
889 mismatch = true;
890 }
891 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
894 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400895 if ( mismatch ) {
896 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500897 DeleteNode( node );
898 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400899 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700900 }
JayXondbfdd8f2014-12-12 20:07:14 -0500901 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 }
903 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800904}
905
Dmitry-Mee3225b12014-09-03 11:03:11 +0400906void XMLNode::DeleteNode( XMLNode* node )
907{
908 if ( node == 0 ) {
909 return;
910 }
911 MemPool* pool = node->_memPool;
912 node->~XMLNode();
913 pool->Free( node );
914}
915
Lee Thomason3cebdc42015-01-05 17:16:28 -0800916void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300917{
918 TIXMLASSERT( insertThis );
919 TIXMLASSERT( insertThis->_document == _document );
920
921 if ( insertThis->_parent )
922 insertThis->_parent->Unlink( insertThis );
923 else
924 insertThis->_memPool->SetTracked();
925}
926
Lee Thomason5492a1c2012-01-23 15:32:10 -0800927// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800928char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800929{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 const char* start = p;
931 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700932 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 }
936 return p;
937 }
938 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700939 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
940 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 flags |= StrPair::COLLAPSE_WHITESPACE;
942 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700943
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 if ( p && *p ) {
946 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300947 }
948 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300949 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 }
951 }
952 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800953}
954
955
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
957{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 }
961 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
962 text->SetCData( this->CData() );
963 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964}
965
966
967bool XMLText::ShallowEqual( const XMLNode* compare ) const
968{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400969 const XMLText* text = compare->ToText();
970 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800971}
972
973
Lee Thomason56bdd022012-02-09 18:16:58 -0800974bool XMLText::Accept( XMLVisitor* visitor ) const
975{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300976 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800978}
979
980
Lee Thomason3f57d272012-01-11 15:30:03 -0800981// --------- XMLComment ---------- //
982
Lee Thomasone4422302012-01-20 17:59:50 -0800983XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800984{
985}
986
987
Lee Thomasonce0763e2012-01-11 15:43:54 -0800988XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800989{
Lee Thomason3f57d272012-01-11 15:30:03 -0800990}
991
992
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800993char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 // Comment parses as text.
996 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001002}
1003
1004
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1006{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001008 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 }
1010 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1011 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001012}
1013
1014
1015bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1016{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001017 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001018 const XMLComment* comment = compare->ToComment();
1019 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001020}
1021
1022
Lee Thomason751da522012-02-10 08:50:51 -08001023bool XMLComment::Accept( XMLVisitor* visitor ) const
1024{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001025 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001026 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001027}
Lee Thomason56bdd022012-02-09 18:16:58 -08001028
1029
Lee Thomason50f97b22012-02-11 16:33:40 -08001030// --------- XMLDeclaration ---------- //
1031
1032XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1033{
1034}
1035
1036
1037XMLDeclaration::~XMLDeclaration()
1038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001040}
1041
1042
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001043char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 // Declaration parses as text.
1046 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001052}
1053
1054
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1056{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001058 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 }
1060 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1061 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001062}
1063
1064
1065bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1066{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001067 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001068 const XMLDeclaration* declaration = compare->ToDeclaration();
1069 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070}
1071
1072
1073
Lee Thomason50f97b22012-02-11 16:33:40 -08001074bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1075{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001076 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001078}
1079
1080// --------- XMLUnknown ---------- //
1081
1082XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1083{
1084}
1085
1086
1087XMLUnknown::~XMLUnknown()
1088{
1089}
1090
1091
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001092char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 // Unknown parses as text.
1095 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001096
Lee Thomason624d43f2012-10-12 10:58:48 -07001097 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001099 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 }
1101 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001102}
1103
1104
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001105XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
1110 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1111 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001112}
1113
1114
1115bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1116{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001117 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001118 const XMLUnknown* unknown = compare->ToUnknown();
1119 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001120}
1121
1122
Lee Thomason50f97b22012-02-11 16:33:40 -08001123bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1124{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001125 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001127}
1128
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001129// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001130
1131const char* XMLAttribute::Name() const
1132{
1133 return _name.GetStr();
1134}
1135
1136const char* XMLAttribute::Value() const
1137{
1138 return _value.GetStr();
1139}
1140
Lee Thomason6f381b72012-03-02 12:59:39 -08001141char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001144 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 if ( !p || !*p ) {
1146 return 0;
1147 }
Lee Thomason22aead12012-01-23 13:29:35 -08001148
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 // Skip white space before =
1150 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001151 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 return 0;
1153 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001154
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 ++p; // move up to opening quote
1156 p = XMLUtil::SkipWhiteSpace( p );
1157 if ( *p != '\"' && *p != '\'' ) {
1158 return 0;
1159 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001160
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 char endTag[2] = { *p, 0 };
1162 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001163
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001166}
1167
1168
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001169void XMLAttribute::SetName( const char* n )
1170{
Lee Thomason624d43f2012-10-12 10:58:48 -07001171 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToInt( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
Lee Thomason2fa81722012-11-09 12:37:46 -08001184XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::ToUnsigned( Value(), value )) {
1187 return XML_NO_ERROR;
1188 }
1189 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190}
1191
1192
Lee Thomason2fa81722012-11-09 12:37:46 -08001193XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( XMLUtil::ToBool( Value(), value )) {
1196 return XML_NO_ERROR;
1197 }
1198 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001199}
1200
1201
Lee Thomason2fa81722012-11-09 12:37:46 -08001202XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( XMLUtil::ToFloat( Value(), value )) {
1205 return XML_NO_ERROR;
1206 }
1207 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001208}
1209
1210
Lee Thomason2fa81722012-11-09 12:37:46 -08001211XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 if ( XMLUtil::ToDouble( Value(), value )) {
1214 return XML_NO_ERROR;
1215 }
1216 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217}
1218
1219
1220void XMLAttribute::SetAttribute( const char* v )
1221{
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001223}
1224
1225
Lee Thomason1ff38e02012-02-14 18:18:16 -08001226void XMLAttribute::SetAttribute( int v )
1227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 char buf[BUF_SIZE];
1229 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001231}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001232
1233
1234void XMLAttribute::SetAttribute( unsigned v )
1235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 char buf[BUF_SIZE];
1237 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239}
1240
1241
1242void XMLAttribute::SetAttribute( bool v )
1243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 char buf[BUF_SIZE];
1245 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001246 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001247}
1248
1249void XMLAttribute::SetAttribute( double v )
1250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 char buf[BUF_SIZE];
1252 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001253 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001254}
1255
1256void XMLAttribute::SetAttribute( float v )
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 char buf[BUF_SIZE];
1259 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001261}
1262
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001263
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001264// --------- XMLElement ---------- //
1265XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001266 _closingType( 0 ),
1267 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001268{
1269}
1270
1271
1272XMLElement::~XMLElement()
1273{
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 while( _rootAttribute ) {
1275 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001276 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001277 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001279}
1280
1281
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001282const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1283{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001284 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1286 return a;
1287 }
1288 }
1289 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001290}
1291
1292
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001293const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 const XMLAttribute* a = FindAttribute( name );
1296 if ( !a ) {
1297 return 0;
1298 }
1299 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1300 return a->Value();
1301 }
1302 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001303}
1304
1305
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001306const char* XMLElement::GetText() const
1307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001309 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 }
1311 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001312}
1313
1314
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001315void XMLElement::SetText( const char* inText )
1316{
Uli Kusterer869bb592014-01-21 01:36:16 +01001317 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001318 FirstChild()->SetValue( inText );
1319 else {
1320 XMLText* theText = GetDocument()->NewText( inText );
1321 InsertFirstChild( theText );
1322 }
1323}
1324
Lee Thomason5bb2d802014-01-24 10:42:57 -08001325
1326void XMLElement::SetText( int v )
1327{
1328 char buf[BUF_SIZE];
1329 XMLUtil::ToStr( v, buf, BUF_SIZE );
1330 SetText( buf );
1331}
1332
1333
1334void XMLElement::SetText( unsigned v )
1335{
1336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
1338 SetText( buf );
1339}
1340
1341
1342void XMLElement::SetText( bool v )
1343{
1344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
1346 SetText( buf );
1347}
1348
1349
1350void XMLElement::SetText( float v )
1351{
1352 char buf[BUF_SIZE];
1353 XMLUtil::ToStr( v, buf, BUF_SIZE );
1354 SetText( buf );
1355}
1356
1357
1358void XMLElement::SetText( double v )
1359{
1360 char buf[BUF_SIZE];
1361 XMLUtil::ToStr( v, buf, BUF_SIZE );
1362 SetText( buf );
1363}
1364
1365
MortenMacFly4ee49f12013-01-14 20:03:14 +01001366XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001369 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 return XML_SUCCESS;
1372 }
1373 return XML_CAN_NOT_CONVERT_TEXT;
1374 }
1375 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001376}
1377
1378
MortenMacFly4ee49f12013-01-14 20:03:14 +01001379XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001382 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001383 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 return XML_SUCCESS;
1385 }
1386 return XML_CAN_NOT_CONVERT_TEXT;
1387 }
1388 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001389}
1390
1391
MortenMacFly4ee49f12013-01-14 20:03:14 +01001392XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001395 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001396 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 return XML_SUCCESS;
1398 }
1399 return XML_CAN_NOT_CONVERT_TEXT;
1400 }
1401 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001402}
1403
1404
MortenMacFly4ee49f12013-01-14 20:03:14 +01001405XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001408 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001409 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 return XML_SUCCESS;
1411 }
1412 return XML_CAN_NOT_CONVERT_TEXT;
1413 }
1414 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001415}
1416
1417
MortenMacFly4ee49f12013-01-14 20:03:14 +01001418XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001421 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001422 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 return XML_SUCCESS;
1424 }
1425 return XML_CAN_NOT_CONVERT_TEXT;
1426 }
1427 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001428}
1429
1430
1431
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001432XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1433{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 XMLAttribute* last = 0;
1435 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1440 break;
1441 }
1442 }
1443 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001444 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1446 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 }
1450 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001454 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
1456 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001457}
1458
1459
U-Stream\Leeae25a442012-02-17 17:48:16 -08001460void XMLElement::DeleteAttribute( const char* name )
1461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1465 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 }
1468 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001471 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 break;
1473 }
1474 prev = a;
1475 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001476}
1477
1478
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001479char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 const char* start = p;
1482 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 // Read the attributes.
1485 while( p ) {
1486 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001487 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 return 0;
1490 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001493 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001494 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1496 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001497 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001498
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001501 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return 0;
1504 }
1505 // There is a minor bug here: if the attribute in the source xml
1506 // document is duplicated, it will not be detected and the
1507 // attribute will be doubly added. However, tracking the 'prevAttribute'
1508 // avoids re-scanning the attribute list. Preferring performance for
1509 // now, may reconsider in the future.
1510 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 }
1513 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 }
1516 prevAttribute = attrib;
1517 }
1518 // end of the tag
1519 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return p+2; // done; sealed element.
1522 }
1523 // end of the tag
1524 else if ( *p == '>' ) {
1525 ++p;
1526 break;
1527 }
1528 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001529 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 return 0;
1531 }
1532 }
1533 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001534}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001535
Dmitry-Mee3225b12014-09-03 11:03:11 +04001536void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1537{
1538 if ( attribute == 0 ) {
1539 return;
1540 }
1541 MemPool* pool = attribute->_memPool;
1542 attribute->~XMLAttribute();
1543 pool->Free( attribute );
1544}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001545
Lee Thomason67d61312012-01-24 16:01:51 -08001546//
1547// <ele></ele>
1548// <ele>foo<b>bar</b></ele>
1549//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001550char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 // Read the element name.
1553 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 // The closing element is the </element> form. It is
1556 // parsed just like a regular element then deleted from
1557 // the DOM.
1558 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 ++p;
1561 }
Lee Thomason67d61312012-01-24 16:01:51 -08001562
Lee Thomason624d43f2012-10-12 10:58:48 -07001563 p = _value.ParseName( p );
1564 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 return 0;
1566 }
Lee Thomason67d61312012-01-24 16:01:51 -08001567
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 return p;
1571 }
Lee Thomason67d61312012-01-24 16:01:51 -08001572
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 p = XMLNode::ParseDeep( p, strPair );
1574 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001575}
1576
1577
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578
1579XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001582 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 }
1584 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1585 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1586 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1587 }
1588 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001589}
1590
1591
1592bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1593{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001594 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 const XMLElement* other = compare->ToElement();
1596 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001597
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 const XMLAttribute* a=FirstAttribute();
1599 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001600
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 while ( a && b ) {
1602 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1603 return false;
1604 }
1605 a = a->Next();
1606 b = b->Next();
1607 }
1608 if ( a || b ) {
1609 // different count
1610 return false;
1611 }
1612 return true;
1613 }
1614 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001615}
1616
1617
Lee Thomason751da522012-02-10 08:50:51 -08001618bool XMLElement::Accept( XMLVisitor* visitor ) const
1619{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001620 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1623 if ( !node->Accept( visitor ) ) {
1624 break;
1625 }
1626 }
1627 }
1628 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001629}
Lee Thomason56bdd022012-02-09 18:16:58 -08001630
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001631
Lee Thomason3f57d272012-01-11 15:30:03 -08001632// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001633
1634// Warning: List must match 'enum XMLError'
1635const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1636 "XML_SUCCESS",
1637 "XML_NO_ATTRIBUTE",
1638 "XML_WRONG_ATTRIBUTE_TYPE",
1639 "XML_ERROR_FILE_NOT_FOUND",
1640 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1641 "XML_ERROR_FILE_READ_ERROR",
1642 "XML_ERROR_ELEMENT_MISMATCH",
1643 "XML_ERROR_PARSING_ELEMENT",
1644 "XML_ERROR_PARSING_ATTRIBUTE",
1645 "XML_ERROR_IDENTIFYING_TAG",
1646 "XML_ERROR_PARSING_TEXT",
1647 "XML_ERROR_PARSING_CDATA",
1648 "XML_ERROR_PARSING_COMMENT",
1649 "XML_ERROR_PARSING_DECLARATION",
1650 "XML_ERROR_PARSING_UNKNOWN",
1651 "XML_ERROR_EMPTY_DOCUMENT",
1652 "XML_ERROR_MISMATCHED_ELEMENT",
1653 "XML_ERROR_PARSING",
1654 "XML_CAN_NOT_CONVERT_TEXT",
1655 "XML_NO_TEXT_NODE"
1656};
1657
1658
Lee Thomason624d43f2012-10-12 10:58:48 -07001659XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 _writeBOM( false ),
1662 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001663 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 _whitespace( whitespace ),
1665 _errorStr1( 0 ),
1666 _errorStr2( 0 ),
1667 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001668{
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001670}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001671
1672
Lee Thomason3f57d272012-01-11 15:30:03 -08001673XMLDocument::~XMLDocument()
1674{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001675 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001676}
1677
1678
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001679void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001680{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001681 DeleteChildren();
1682
Dmitry-Meab37df82014-11-28 12:08:36 +03001683#ifdef DEBUG
1684 const bool hadError = Error();
1685#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001686 _errorID = XML_NO_ERROR;
1687 _errorStr1 = 0;
1688 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001689
Lee Thomason624d43f2012-10-12 10:58:48 -07001690 delete [] _charBuffer;
1691 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001692
1693#if 0
1694 _textPool.Trace( "text" );
1695 _elementPool.Trace( "element" );
1696 _commentPool.Trace( "comment" );
1697 _attributePool.Trace( "attribute" );
1698#endif
1699
1700#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001701 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001702 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1703 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1704 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1705 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1706 }
1707#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001708}
1709
Lee Thomason3f57d272012-01-11 15:30:03 -08001710
Lee Thomason2c85a712012-01-31 08:24:24 -08001711XMLElement* XMLDocument::NewElement( const char* name )
1712{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001713 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1715 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 ele->SetName( name );
1717 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001718}
1719
1720
Lee Thomason1ff38e02012-02-14 18:18:16 -08001721XMLComment* XMLDocument::NewComment( const char* str )
1722{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001723 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1725 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 comment->SetValue( str );
1727 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001728}
1729
1730
1731XMLText* XMLDocument::NewText( const char* str )
1732{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001733 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1735 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 text->SetValue( str );
1737 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001738}
1739
1740
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001741XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1742{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001743 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1745 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1747 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001748}
1749
1750
1751XMLUnknown* XMLDocument::NewUnknown( const char* str )
1752{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001753 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1755 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 unk->SetValue( str );
1757 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001758}
1759
Dmitry-Me01578db2014-08-19 10:18:48 +04001760static FILE* callfopen( const char* filepath, const char* mode )
1761{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001762 TIXMLASSERT( filepath );
1763 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001764#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1765 FILE* fp = 0;
1766 errno_t err = fopen_s( &fp, filepath, mode );
1767 if ( err ) {
1768 return 0;
1769 }
1770#else
1771 FILE* fp = fopen( filepath, mode );
1772#endif
1773 return fp;
1774}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001775
1776void XMLDocument::DeleteNode( XMLNode* node ) {
1777 TIXMLASSERT( node );
1778 TIXMLASSERT(node->_document == this );
1779 if (node->_parent) {
1780 node->_parent->DeleteChild( node );
1781 }
1782 else {
1783 // Isn't in the tree.
1784 // Use the parent delete.
1785 // Also, we need to mark it tracked: we 'know'
1786 // it was never used.
1787 node->_memPool->SetTracked();
1788 // Call the static XMLNode version:
1789 XMLNode::DeleteNode(node);
1790 }
1791}
1792
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001793
Lee Thomason2fa81722012-11-09 12:37:46 -08001794XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001796 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001797 FILE* fp = callfopen( filename, "rb" );
1798 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001800 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 }
1802 LoadFile( fp );
1803 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001805}
1806
1807
Lee Thomason2fa81722012-11-09 12:37:46 -08001808XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001809{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001810 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001811
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001812 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001813 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001814 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1815 return _errorID;
1816 }
1817
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001819 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001821 if ( filelength == -1L ) {
1822 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1823 return _errorID;
1824 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001826 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001828 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001829 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001831
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _charBuffer = new char[size+1];
1833 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 if ( read != size ) {
1835 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001838
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001840
Dmitry-Me97476b72015-01-01 16:15:57 +03001841 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001843}
1844
1845
Lee Thomason2fa81722012-11-09 12:37:46 -08001846XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001847{
Dmitry-Me01578db2014-08-19 10:18:48 +04001848 FILE* fp = callfopen( filename, "w" );
1849 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
1853 SaveFile(fp, compact);
1854 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001856}
1857
1858
Lee Thomason2fa81722012-11-09 12:37:46 -08001859XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001860{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 XMLPrinter stream( fp, compact );
1862 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001864}
1865
Lee Thomason1ff38e02012-02-14 18:18:16 -08001866
Lee Thomason2fa81722012-11-09 12:37:46 -08001867XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001868{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001869 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001870
Lee Thomason82d32002014-02-21 22:47:18 -08001871 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 }
1875 if ( len == (size_t)(-1) ) {
1876 len = strlen( p );
1877 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 _charBuffer = new char[ len+1 ];
1879 memcpy( _charBuffer, p, len );
1880 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001881
Dmitry-Me97476b72015-01-01 16:15:57 +03001882 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001883 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001884 // clean up now essentially dangling memory.
1885 // and the parse fail can put objects in the
1886 // pools that are dead and inaccessible.
1887 DeleteChildren();
1888 _elementPool.Clear();
1889 _attributePool.Clear();
1890 _textPool.Clear();
1891 _commentPool.Clear();
1892 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001894}
1895
1896
PKEuS1c5f99e2013-07-06 11:28:39 +02001897void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 XMLPrinter stdStreamer( stdout );
1900 if ( !streamer ) {
1901 streamer = &stdStreamer;
1902 }
1903 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001904}
1905
1906
Lee Thomason2fa81722012-11-09 12:37:46 -08001907void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001908{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001909 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 _errorID = error;
1911 _errorStr1 = str1;
1912 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001913}
1914
Lee Thomason331596e2014-09-11 14:56:43 -07001915const char* XMLDocument::ErrorName() const
1916{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001917 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001918 return _errorNames[_errorID];
1919}
Lee Thomason5cae8972012-01-24 18:03:07 -08001920
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001921void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001922{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001923 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 static const int LEN = 20;
1925 char buf1[LEN] = { 0 };
1926 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001927
Lee Thomason624d43f2012-10-12 10:58:48 -07001928 if ( _errorStr1 ) {
1929 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001931 if ( _errorStr2 ) {
1932 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001934
Lee Thomason331596e2014-09-11 14:56:43 -07001935 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1936 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001938}
1939
Dmitry-Me97476b72015-01-01 16:15:57 +03001940void XMLDocument::Parse()
1941{
1942 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1943 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001944 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001945 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001946 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001947 if ( !*p ) {
1948 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1949 return;
1950 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001951 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001952}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001953
PKEuS1bfb9542013-08-04 13:51:17 +02001954XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 _elementJustOpened( false ),
1956 _firstElement( true ),
1957 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001958 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 _textDepth( -1 ),
1960 _processEntities( true ),
1961 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _entityFlag[i] = false;
1965 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 }
1967 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001968 const char entityValue = entities[i].value;
1969 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1970 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001972 _restrictedEntityFlag[(unsigned char)'&'] = true;
1973 _restrictedEntityFlag[(unsigned char)'<'] = true;
1974 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001976}
1977
1978
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001979void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001980{
1981 va_list va;
1982 va_start( va, format );
1983
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 if ( _fp ) {
1985 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 }
1987 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001988#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001989 #if defined(WINCE)
1990 int len = 512;
1991 do {
1992 len = len*2;
1993 char* str = new char[len]();
1994 len = _vsnprintf(str, len, format, va);
1995 delete[] str;
1996 }while (len < 0);
1997 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001998 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001999 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000#else
2001 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002002#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 // Close out and re-start the va-args
2004 va_end( va );
2005 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002006 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002007 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2008#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002009 #if defined(WINCE)
2010 _vsnprintf( p, len+1, format, va );
2011 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002012 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002013 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002014#else
2015 vsnprintf( p, len+1, format, va );
2016#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002018 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002019}
2020
2021
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002022void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 for( int i=0; i<depth; ++i ) {
2025 Print( " " );
2026 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002027}
2028
2029
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002030void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 // Look for runs of bytes between entities to print.
2033 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002034
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002036 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 while ( *q ) {
2038 // Remember, char is sometimes signed. (How many times has that bitten me?)
2039 if ( *q > 0 && *q < ENTITY_RANGE ) {
2040 // Check for entities. If one is found, flush
2041 // the stream up until the entity, write the
2042 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002043 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 while ( p < q ) {
2045 Print( "%c", *p );
2046 ++p;
2047 }
2048 for( int i=0; i<NUM_ENTITIES; ++i ) {
2049 if ( entities[i].value == *q ) {
2050 Print( "&%s;", entities[i].pattern );
2051 break;
2052 }
2053 }
2054 ++p;
2055 }
2056 }
2057 ++q;
2058 }
2059 }
2060 // Flush the remaining string. This will be the entire
2061 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 Print( "%s", p );
2064 }
Lee Thomason857b8682012-01-25 17:50:25 -08002065}
2066
U-Stream\Leeae25a442012-02-17 17:48:16 -08002067
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002068void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002071 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 -07002072 Print( "%s", bom );
2073 }
2074 if ( writeDec ) {
2075 PushDeclaration( "xml version=\"1.0\"" );
2076 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002077}
2078
2079
Uli Kusterer593a33d2014-02-01 12:48:51 +01002080void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002081{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002082 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002084
Uli Kusterer593a33d2014-02-01 12:48:51 +01002085 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002087 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002088 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 _elementJustOpened = true;
2094 _firstElement = false;
2095 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002096}
2097
2098
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002099void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002100{
Lee Thomason624d43f2012-10-12 10:58:48 -07002101 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 Print( " %s=\"", name );
2103 PrintString( value, false );
2104 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002105}
2106
2107
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108void XMLPrinter::PushAttribute( const char* name, int v )
2109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 char buf[BUF_SIZE];
2111 XMLUtil::ToStr( v, buf, BUF_SIZE );
2112 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002113}
2114
2115
2116void XMLPrinter::PushAttribute( const char* name, unsigned v )
2117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 char buf[BUF_SIZE];
2119 XMLUtil::ToStr( v, buf, BUF_SIZE );
2120 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002121}
2122
2123
2124void XMLPrinter::PushAttribute( const char* name, bool v )
2125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 char buf[BUF_SIZE];
2127 XMLUtil::ToStr( v, buf, BUF_SIZE );
2128 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002129}
2130
2131
2132void XMLPrinter::PushAttribute( const char* name, double v )
2133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 char buf[BUF_SIZE];
2135 XMLUtil::ToStr( v, buf, BUF_SIZE );
2136 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002137}
2138
2139
Uli Kustererca412e82014-02-01 13:35:05 +01002140void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002141{
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 --_depth;
2143 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002144
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( "/>" );
2147 }
2148 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002149 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 }
2153 Print( "</%s>", name );
2154 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002155
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 if ( _textDepth == _depth ) {
2157 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
Uli Kustererca412e82014-02-01 13:35:05 +01002159 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 Print( "\n" );
2161 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002163}
2164
2165
Dmitry-Mea092bc12014-12-23 17:57:05 +03002166void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002167{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002168 if ( !_elementJustOpened ) {
2169 return;
2170 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002173}
2174
2175
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002176void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002177{
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002179
Dmitry-Mea092bc12014-12-23 17:57:05 +03002180 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 if ( cdata ) {
2182 Print( "<![CDATA[" );
2183 Print( "%s", text );
2184 Print( "]]>" );
2185 }
2186 else {
2187 PrintString( text, true );
2188 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002189}
2190
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002191void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 char buf[BUF_SIZE];
2194 XMLUtil::ToStr( value, buf, BUF_SIZE );
2195 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002196}
2197
2198
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002199void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 char buf[BUF_SIZE];
2202 XMLUtil::ToStr( value, buf, BUF_SIZE );
2203 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002204}
2205
2206
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002207void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 char buf[BUF_SIZE];
2210 XMLUtil::ToStr( value, buf, BUF_SIZE );
2211 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002212}
2213
2214
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002215void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 char buf[BUF_SIZE];
2218 XMLUtil::ToStr( value, buf, BUF_SIZE );
2219 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002220}
2221
2222
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002223void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 char buf[BUF_SIZE];
2226 XMLUtil::ToStr( value, buf, BUF_SIZE );
2227 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002228}
2229
Lee Thomason5cae8972012-01-24 18:03:07 -08002230
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002231void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002232{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002233 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002240}
Lee Thomason751da522012-02-10 08:50:51 -08002241
2242
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002243void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002245 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002252}
2253
2254
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002255void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002256{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002257 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002260 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002262 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002264}
2265
2266
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002267bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002268{
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 if ( doc.HasBOM() ) {
2271 PushHeader( true, false );
2272 }
2273 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002274}
2275
2276
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002277bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002278{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002279 const XMLElement* parentElem = element.Parent()->ToElement();
2280 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2281 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 while ( attribute ) {
2283 PushAttribute( attribute->Name(), attribute->Value() );
2284 attribute = attribute->Next();
2285 }
2286 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002287}
2288
2289
Uli Kustererca412e82014-02-01 13:35:05 +01002290bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002291{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002292 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002294}
2295
2296
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002297bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 PushText( text.Value(), text.CData() );
2300 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002301}
2302
2303
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002304bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 PushComment( comment.Value() );
2307 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002308}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002309
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002310bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 PushDeclaration( declaration.Value() );
2313 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002314}
2315
2316
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002317bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 PushUnknown( unknown.Value() );
2320 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002321}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002322
Lee Thomason685b8952012-11-12 13:00:06 -08002323} // namespace tinyxml2
2324