blob: 3d7e2d18f27dfdf8d4670ae79242cdcd28f1ccd9 [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;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300231 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
232 if ( adjusted == 0 ) {
233 *q = *p;
234 ++p;
235 ++q;
236 }
237 else {
238 TIXMLASSERT( 0 <= len && len <= buflen );
239 TIXMLASSERT( q + len <= adjusted );
240 p = adjusted;
241 memcpy( q, buf, len );
242 q += len;
243 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700244 }
245 else {
246 int i=0;
247 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400248 const Entity& entity = entities[i];
249 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
250 && *( p + entity.length + 1 ) == ';' ) {
251 // Found an entity - convert.
252 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700253 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400254 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 break;
256 }
257 }
258 if ( i == NUM_ENTITIES ) {
259 // fixme: treat as error?
260 ++p;
261 ++q;
262 }
263 }
264 }
265 else {
266 *q = *p;
267 ++p;
268 ++q;
269 }
270 }
271 *q = 0;
272 }
273 // The loop below has plenty going on, and this
274 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700276 CollapseWhitespace();
277 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700279 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300280 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700281 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800282}
283
Lee Thomason2c85a712012-01-31 08:24:24 -0800284
Lee Thomasone4422302012-01-20 17:59:50 -0800285
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800286
Lee Thomason56bdd022012-02-09 18:16:58 -0800287// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800288
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800289const char* XMLUtil::ReadBOM( const char* p, bool* bom )
290{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300291 TIXMLASSERT( p );
292 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 *bom = false;
294 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
295 // Check for BOM:
296 if ( *(pu+0) == TIXML_UTF_LEAD_0
297 && *(pu+1) == TIXML_UTF_LEAD_1
298 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
299 *bom = true;
300 p += 3;
301 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300302 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304}
305
306
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800307void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 const unsigned long BYTE_MASK = 0xBF;
310 const unsigned long BYTE_MARK = 0x80;
311 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800312
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 if (input < 0x80) {
314 *length = 1;
315 }
316 else if ( input < 0x800 ) {
317 *length = 2;
318 }
319 else if ( input < 0x10000 ) {
320 *length = 3;
321 }
322 else if ( input < 0x200000 ) {
323 *length = 4;
324 }
325 else {
326 *length = 0; // This code won't covert this correctly anyway.
327 return;
328 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800329
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800331
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Scary scary fall throughs.
333 switch (*length) {
334 case 4:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 3:
339 --output;
340 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
341 input >>= 6;
342 case 2:
343 --output;
344 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
345 input >>= 6;
346 case 1:
347 --output;
348 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100349 default:
350 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352}
353
354
355const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 // Presume an entity, and pull it out.
358 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( *(p+1) == '#' && *(p+2) ) {
361 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300362 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 ptrdiff_t delta = 0;
364 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800365 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 if ( *(p+2) == 'x' ) {
368 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300369 const char* q = p+3;
370 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700371 return 0;
372 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800373
Lee Thomason7e67bc82015-01-12 14:05:12 -0800374 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Dmitry-Me9f56e122015-01-12 10:07:54 +0300376 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 return 0;
378 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800379 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800380
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700381 delta = q-p;
382 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800383
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 while ( *q != 'x' ) {
385 if ( *q >= '0' && *q <= '9' ) {
386 ucs += mult * (*q - '0');
387 }
388 else if ( *q >= 'a' && *q <= 'f' ) {
389 ucs += mult * (*q - 'a' + 10);
390 }
391 else if ( *q >= 'A' && *q <= 'F' ) {
392 ucs += mult * (*q - 'A' + 10 );
393 }
394 else {
395 return 0;
396 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300397 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 mult *= 16;
399 --q;
400 }
401 }
402 else {
403 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300404 const char* q = p+2;
405 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 return 0;
407 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomason7e67bc82015-01-12 14:05:12 -0800409 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Dmitry-Me9f56e122015-01-12 10:07:54 +0300411 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 return 0;
413 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800414 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800415
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 delta = q-p;
417 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800418
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 while ( *q != '#' ) {
420 if ( *q >= '0' && *q <= '9' ) {
421 ucs += mult * (*q - '0');
422 }
423 else {
424 return 0;
425 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300426 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 mult *= 10;
428 --q;
429 }
430 }
431 // convert the UCS to UTF-8
432 ConvertUTF32ToUTF8( ucs, value, length );
433 return p + delta + 1;
434 }
435 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800436}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800437
438
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700439void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700442}
443
444
445void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700448}
449
450
451void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700454}
455
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800456/*
457 ToStr() of a number is a very tricky topic.
458 https://github.com/leethomason/tinyxml2/issues/106
459*/
Lee Thomason21be8822012-07-15 17:27:22 -0700460void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
461{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800462 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700463}
464
465
466void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
467{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800468 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471
472bool XMLUtil::ToInt( const char* str, int* value )
473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700474 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
475 return true;
476 }
477 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700478}
479
480bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
483 return true;
484 }
485 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700486}
487
488bool XMLUtil::ToBool( const char* str, bool* value )
489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 int ival = 0;
491 if ( ToInt( str, &ival )) {
492 *value = (ival==0) ? false : true;
493 return true;
494 }
495 if ( StringEqual( str, "true" ) ) {
496 *value = true;
497 return true;
498 }
499 else if ( StringEqual( str, "false" ) ) {
500 *value = false;
501 return true;
502 }
503 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700504}
505
506
507bool XMLUtil::ToFloat( const char* str, float* value )
508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
510 return true;
511 }
512 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700513}
514
515bool XMLUtil::ToDouble( const char* str, double* value )
516{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
518 return true;
519 }
520 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700521}
522
523
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700524char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525{
Dmitry-Me02384662015-03-03 16:02:13 +0300526 TIXMLASSERT( node );
527 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400528 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300530 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300531 *node = 0;
532 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 return p;
534 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800535
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800537 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 static const char* xmlHeader = { "<?" };
539 static const char* commentHeader = { "<!--" };
540 static const char* dtdHeader = { "<!" };
541 static const char* cdataHeader = { "<![CDATA[" };
542 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800543
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 static const int xmlHeaderLen = 2;
545 static const int commentHeaderLen = 4;
546 static const int dtdHeaderLen = 2;
547 static const int cdataHeaderLen = 9;
548 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800549
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
551 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400552 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300554 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
556 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p += xmlHeaderLen;
558 }
559 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300560 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700561 returnNode = new (_commentPool.Alloc()) XMLComment( this );
562 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 p += commentHeaderLen;
564 }
565 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300566 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 p += cdataHeaderLen;
571 text->SetCData( true );
572 }
573 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300574 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700575 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
576 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 p += dtdHeaderLen;
578 }
579 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300580 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 returnNode = new (_elementPool.Alloc()) XMLElement( this );
582 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 p += elementHeaderLen;
584 }
585 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300586 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700587 returnNode = new (_textPool.Alloc()) XMLText( this );
588 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 p = start; // Back it up, all the text counts.
590 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800591
Dmitry-Me02384662015-03-03 16:02:13 +0300592 TIXMLASSERT( returnNode );
593 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 *node = returnNode;
595 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596}
597
598
Lee Thomason751da522012-02-10 08:50:51 -0800599bool XMLDocument::Accept( XMLVisitor* visitor ) const
600{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300601 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( visitor->VisitEnter( *this ) ) {
603 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
604 if ( !node->Accept( visitor ) ) {
605 break;
606 }
607 }
608 }
609 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800610}
Lee Thomason56bdd022012-02-09 18:16:58 -0800611
612
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800613// --------- XMLNode ----------- //
614
615XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 _document( doc ),
617 _parent( 0 ),
618 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200619 _prev( 0 ), _next( 0 ),
620 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800621{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622}
623
624
625XMLNode::~XMLNode()
626{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 if ( _parent ) {
629 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800631}
632
Michael Daumling21626882013-10-22 17:03:37 +0200633const char* XMLNode::Value() const
634{
635 return _value.GetStr();
636}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800637
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800638void XMLNode::SetValue( const char* str, bool staticMem )
639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
643 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800646}
647
648
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800649void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800650{
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300652 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700655
Dmitry-Mee3225b12014-09-03 11:03:11 +0400656 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800659}
660
661
662void XMLNode::Unlink( XMLNode* child )
663{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300664 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 if ( child == _firstChild ) {
667 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 if ( child == _lastChild ) {
670 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
Lee Thomasond923c672012-01-23 08:44:25 -0800672
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 if ( child->_prev ) {
674 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 if ( child->_next ) {
677 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700679 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680}
681
682
U-Stream\Leeae25a442012-02-17 17:48:16 -0800683void XMLNode::DeleteChild( XMLNode* node )
684{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300685 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300686 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400688 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800689}
690
691
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
693{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300694 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300695 if ( addThis->_document != _document ) {
696 TIXMLASSERT( false );
697 return 0;
698 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800699 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700700
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 if ( _lastChild ) {
702 TIXMLASSERT( _firstChild );
703 TIXMLASSERT( _lastChild->_next == 0 );
704 _lastChild->_next = addThis;
705 addThis->_prev = _lastChild;
706 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 }
710 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 TIXMLASSERT( _firstChild == 0 );
712 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 addThis->_prev = 0;
715 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700718 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800719}
720
721
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
723{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300724 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300725 if ( addThis->_document != _document ) {
726 TIXMLASSERT( false );
727 return 0;
728 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800729 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 if ( _firstChild ) {
732 TIXMLASSERT( _lastChild );
733 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 _firstChild->_prev = addThis;
736 addThis->_next = _firstChild;
737 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800738
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 }
741 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 TIXMLASSERT( _lastChild == 0 );
743 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800744
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 addThis->_prev = 0;
746 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400749 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750}
751
752
753XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
754{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300755 TIXMLASSERT( addThis );
756 if ( addThis->_document != _document ) {
757 TIXMLASSERT( false );
758 return 0;
759 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700760
Dmitry-Meabb2d042014-12-09 12:59:31 +0300761 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700762
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300764 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 return 0;
766 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800767
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 // The last node or the only node.
770 return InsertEndChild( addThis );
771 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800772 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 addThis->_prev = afterThis;
774 addThis->_next = afterThis->_next;
775 afterThis->_next->_prev = addThis;
776 afterThis->_next = addThis;
777 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800779}
780
781
782
783
Lee Thomason56bdd022012-02-09 18:16:58 -0800784const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800785{
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 XMLElement* element = node->ToElement();
788 if ( element ) {
789 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
790 return element;
791 }
792 }
793 }
794 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800795}
796
797
Lee Thomason56bdd022012-02-09 18:16:58 -0800798const XMLElement* XMLNode::LastChildElement( const char* value ) const
799{
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 XMLElement* element = node->ToElement();
802 if ( element ) {
803 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
804 return element;
805 }
806 }
807 }
808 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800809}
810
811
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800812const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
813{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400814 for( XMLNode* node=this->_next; node; node = node->_next ) {
815 const XMLElement* element = node->ToElement();
816 if ( element
817 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
818 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
820 }
821 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800822}
823
824
825const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
826{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400827 for( XMLNode* node=_prev; node; node = node->_prev ) {
828 const XMLElement* element = node->ToElement();
829 if ( element
830 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
831 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
833 }
834 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800835}
836
837
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800838char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800839{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 // This is a recursive method, but thinking about it "at the current level"
841 // it is a pretty simple flat list:
842 // <foo/>
843 // <!-- comment -->
844 //
845 // With a special case:
846 // <foo>
847 // </foo>
848 // <!-- comment -->
849 //
850 // Where the closing element (/foo) *must* be the next thing after the opening
851 // element, and the names must match. BUT the tricky bit is that the closing
852 // element will be read by the child.
853 //
854 // 'endTag' is the end tag for this node, it is returned by a call to a child.
855 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 while( p && *p ) {
858 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800859
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300861 if ( node == 0 ) {
862 break;
863 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800864
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 StrPair endTag;
866 p = node->ParseDeep( p, &endTag );
867 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400868 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700869 if ( !_document->Error() ) {
870 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 }
872 break;
873 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400875 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500877 // We read the end tag. Return it to the parent.
878 if ( ele->ClosingType() == XMLElement::CLOSING ) {
879 if ( parentEnd ) {
880 ele->_value.TransferTo( parentEnd );
881 }
882 node->_memPool->SetTracked(); // created and then immediately deleted.
883 DeleteNode( node );
884 return p;
885 }
886
887 // Handle an end tag returned to this level.
888 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400889 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300890 if ( endTag.Empty() ) {
891 if ( ele->ClosingType() == XMLElement::OPEN ) {
892 mismatch = true;
893 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300895 else {
896 if ( ele->ClosingType() != XMLElement::OPEN ) {
897 mismatch = true;
898 }
899 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400900 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 }
902 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400903 if ( mismatch ) {
904 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500905 DeleteNode( node );
906 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400907 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 }
JayXondbfdd8f2014-12-12 20:07:14 -0500909 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700910 }
911 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800912}
913
Dmitry-Mee3225b12014-09-03 11:03:11 +0400914void XMLNode::DeleteNode( XMLNode* node )
915{
916 if ( node == 0 ) {
917 return;
918 }
919 MemPool* pool = node->_memPool;
920 node->~XMLNode();
921 pool->Free( node );
922}
923
Lee Thomason3cebdc42015-01-05 17:16:28 -0800924void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300925{
926 TIXMLASSERT( insertThis );
927 TIXMLASSERT( insertThis->_document == _document );
928
929 if ( insertThis->_parent )
930 insertThis->_parent->Unlink( insertThis );
931 else
932 insertThis->_memPool->SetTracked();
933}
934
Lee Thomason5492a1c2012-01-23 15:32:10 -0800935// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800936char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 const char* start = p;
939 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 return p;
945 }
946 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700947 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
948 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 flags |= StrPair::COLLAPSE_WHITESPACE;
950 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700951
Lee Thomason624d43f2012-10-12 10:58:48 -0700952 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( p && *p ) {
954 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300955 }
956 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300957 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 }
960 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800961}
962
963
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
965{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
970 text->SetCData( this->CData() );
971 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
975bool XMLText::ShallowEqual( const XMLNode* compare ) const
976{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400977 const XMLText* text = compare->ToText();
978 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800979}
980
981
Lee Thomason56bdd022012-02-09 18:16:58 -0800982bool XMLText::Accept( XMLVisitor* visitor ) const
983{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300984 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800986}
987
988
Lee Thomason3f57d272012-01-11 15:30:03 -0800989// --------- XMLComment ---------- //
990
Lee Thomasone4422302012-01-20 17:59:50 -0800991XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800992{
993}
994
995
Lee Thomasonce0763e2012-01-11 15:43:54 -0800996XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800997{
Lee Thomason3f57d272012-01-11 15:30:03 -0800998}
999
1000
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001001char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001002{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 // Comment parses as text.
1004 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001005 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001007 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 }
1009 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001010}
1011
1012
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001013XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1014{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001016 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 }
1018 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1019 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001020}
1021
1022
1023bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1024{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001025 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001026 const XMLComment* comment = compare->ToComment();
1027 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001028}
1029
1030
Lee Thomason751da522012-02-10 08:50:51 -08001031bool XMLComment::Accept( XMLVisitor* visitor ) const
1032{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001033 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001035}
Lee Thomason56bdd022012-02-09 18:16:58 -08001036
1037
Lee Thomason50f97b22012-02-11 16:33:40 -08001038// --------- XMLDeclaration ---------- //
1039
1040XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1041{
1042}
1043
1044
1045XMLDeclaration::~XMLDeclaration()
1046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001048}
1049
1050
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001051char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001052{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 // Declaration parses as text.
1054 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001055 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001057 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 }
1059 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001060}
1061
1062
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001063XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1064{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001066 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
1068 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1069 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070}
1071
1072
1073bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1074{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001075 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001076 const XMLDeclaration* declaration = compare->ToDeclaration();
1077 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001078}
1079
1080
1081
Lee Thomason50f97b22012-02-11 16:33:40 -08001082bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1083{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001084 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001086}
1087
1088// --------- XMLUnknown ---------- //
1089
1090XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1091{
1092}
1093
1094
1095XMLUnknown::~XMLUnknown()
1096{
1097}
1098
1099
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001100char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 // Unknown parses as text.
1103 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001104
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 }
1109 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001110}
1111
1112
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001113XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001116 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 }
1118 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1119 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001120}
1121
1122
1123bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1124{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001125 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001126 const XMLUnknown* unknown = compare->ToUnknown();
1127 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001128}
1129
1130
Lee Thomason50f97b22012-02-11 16:33:40 -08001131bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1132{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001133 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001135}
1136
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001137// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001138
1139const char* XMLAttribute::Name() const
1140{
1141 return _name.GetStr();
1142}
1143
1144const char* XMLAttribute::Value() const
1145{
1146 return _value.GetStr();
1147}
1148
Lee Thomason6f381b72012-03-02 12:59:39 -08001149char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( !p || !*p ) {
1154 return 0;
1155 }
Lee Thomason22aead12012-01-23 13:29:35 -08001156
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 // Skip white space before =
1158 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001159 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 return 0;
1161 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001162
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 ++p; // move up to opening quote
1164 p = XMLUtil::SkipWhiteSpace( p );
1165 if ( *p != '\"' && *p != '\'' ) {
1166 return 0;
1167 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001168
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 char endTag[2] = { *p, 0 };
1170 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001171
Lee Thomason624d43f2012-10-12 10:58:48 -07001172 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001174}
1175
1176
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001177void XMLAttribute::SetName( const char* n )
1178{
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001180}
1181
1182
Lee Thomason2fa81722012-11-09 12:37:46 -08001183XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::ToInt( Value(), value )) {
1186 return XML_NO_ERROR;
1187 }
1188 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189}
1190
1191
Lee Thomason2fa81722012-11-09 12:37:46 -08001192XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 if ( XMLUtil::ToUnsigned( Value(), value )) {
1195 return XML_NO_ERROR;
1196 }
1197 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001198}
1199
1200
Lee Thomason2fa81722012-11-09 12:37:46 -08001201XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( XMLUtil::ToBool( Value(), value )) {
1204 return XML_NO_ERROR;
1205 }
1206 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
Lee Thomason2fa81722012-11-09 12:37:46 -08001210XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 if ( XMLUtil::ToFloat( Value(), value )) {
1213 return XML_NO_ERROR;
1214 }
1215 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001216}
1217
1218
Lee Thomason2fa81722012-11-09 12:37:46 -08001219XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 if ( XMLUtil::ToDouble( Value(), value )) {
1222 return XML_NO_ERROR;
1223 }
1224 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001225}
1226
1227
1228void XMLAttribute::SetAttribute( const char* v )
1229{
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001231}
1232
1233
Lee Thomason1ff38e02012-02-14 18:18:16 -08001234void XMLAttribute::SetAttribute( int 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 Thomason1ff38e02012-02-14 18:18:16 -08001239}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240
1241
1242void XMLAttribute::SetAttribute( unsigned 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
1249
1250void XMLAttribute::SetAttribute( bool v )
1251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 char buf[BUF_SIZE];
1253 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001255}
1256
1257void XMLAttribute::SetAttribute( double v )
1258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 char buf[BUF_SIZE];
1260 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001262}
1263
1264void XMLAttribute::SetAttribute( float v )
1265{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 char buf[BUF_SIZE];
1267 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001268 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001269}
1270
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001271
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001272// --------- XMLElement ---------- //
1273XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 _closingType( 0 ),
1275 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001276{
1277}
1278
1279
1280XMLElement::~XMLElement()
1281{
Lee Thomason624d43f2012-10-12 10:58:48 -07001282 while( _rootAttribute ) {
1283 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001284 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001285 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001287}
1288
1289
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001290const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1291{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001292 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1294 return a;
1295 }
1296 }
1297 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001298}
1299
1300
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001301const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 const XMLAttribute* a = FindAttribute( name );
1304 if ( !a ) {
1305 return 0;
1306 }
1307 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1308 return a->Value();
1309 }
1310 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001311}
1312
1313
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001314const char* XMLElement::GetText() const
1315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001317 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 }
1319 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001320}
1321
1322
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001323void XMLElement::SetText( const char* inText )
1324{
Uli Kusterer869bb592014-01-21 01:36:16 +01001325 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001326 FirstChild()->SetValue( inText );
1327 else {
1328 XMLText* theText = GetDocument()->NewText( inText );
1329 InsertFirstChild( theText );
1330 }
1331}
1332
Lee Thomason5bb2d802014-01-24 10:42:57 -08001333
1334void XMLElement::SetText( int v )
1335{
1336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
1338 SetText( buf );
1339}
1340
1341
1342void XMLElement::SetText( unsigned v )
1343{
1344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
1346 SetText( buf );
1347}
1348
1349
1350void XMLElement::SetText( bool v )
1351{
1352 char buf[BUF_SIZE];
1353 XMLUtil::ToStr( v, buf, BUF_SIZE );
1354 SetText( buf );
1355}
1356
1357
1358void XMLElement::SetText( float v )
1359{
1360 char buf[BUF_SIZE];
1361 XMLUtil::ToStr( v, buf, BUF_SIZE );
1362 SetText( buf );
1363}
1364
1365
1366void XMLElement::SetText( double v )
1367{
1368 char buf[BUF_SIZE];
1369 XMLUtil::ToStr( v, buf, BUF_SIZE );
1370 SetText( buf );
1371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001377 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001390 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001416 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 return XML_SUCCESS;
1419 }
1420 return XML_CAN_NOT_CONVERT_TEXT;
1421 }
1422 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
MortenMacFly4ee49f12013-01-14 20:03:14 +01001426XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001429 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001430 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 return XML_SUCCESS;
1432 }
1433 return XML_CAN_NOT_CONVERT_TEXT;
1434 }
1435 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001436}
1437
1438
1439
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 XMLAttribute* last = 0;
1443 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1448 break;
1449 }
1450 }
1451 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001452 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1454 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 }
1458 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001462 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465}
1466
1467
U-Stream\Leeae25a442012-02-17 17:48:16 -08001468void XMLElement::DeleteAttribute( const char* name )
1469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1473 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 }
1476 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001479 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 break;
1481 }
1482 prev = a;
1483 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001484}
1485
1486
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001487char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 const char* start = p;
1490 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 // Read the attributes.
1493 while( p ) {
1494 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001495 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 return 0;
1498 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001499
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001501 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001502 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1504 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001505 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001506
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001509 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return 0;
1512 }
1513 // There is a minor bug here: if the attribute in the source xml
1514 // document is duplicated, it will not be detected and the
1515 // attribute will be doubly added. However, tracking the 'prevAttribute'
1516 // avoids re-scanning the attribute list. Preferring performance for
1517 // now, may reconsider in the future.
1518 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 }
1521 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 }
1524 prevAttribute = attrib;
1525 }
1526 // end of the tag
1527 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001528 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 return p+2; // done; sealed element.
1530 }
1531 // end of the tag
1532 else if ( *p == '>' ) {
1533 ++p;
1534 break;
1535 }
1536 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 return 0;
1539 }
1540 }
1541 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001542}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001543
Dmitry-Mee3225b12014-09-03 11:03:11 +04001544void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1545{
1546 if ( attribute == 0 ) {
1547 return;
1548 }
1549 MemPool* pool = attribute->_memPool;
1550 attribute->~XMLAttribute();
1551 pool->Free( attribute );
1552}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001553
Lee Thomason67d61312012-01-24 16:01:51 -08001554//
1555// <ele></ele>
1556// <ele>foo<b>bar</b></ele>
1557//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001558char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 // Read the element name.
1561 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001562
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 // The closing element is the </element> form. It is
1564 // parsed just like a regular element then deleted from
1565 // the DOM.
1566 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 ++p;
1569 }
Lee Thomason67d61312012-01-24 16:01:51 -08001570
Lee Thomason624d43f2012-10-12 10:58:48 -07001571 p = _value.ParseName( p );
1572 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 return 0;
1574 }
Lee Thomason67d61312012-01-24 16:01:51 -08001575
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 return p;
1579 }
Lee Thomason67d61312012-01-24 16:01:51 -08001580
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 p = XMLNode::ParseDeep( p, strPair );
1582 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001583}
1584
1585
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001586
1587XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 }
1592 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1593 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1594 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1595 }
1596 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001597}
1598
1599
1600bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1601{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001602 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 const XMLElement* other = compare->ToElement();
1604 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001605
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 const XMLAttribute* a=FirstAttribute();
1607 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001608
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 while ( a && b ) {
1610 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1611 return false;
1612 }
1613 a = a->Next();
1614 b = b->Next();
1615 }
1616 if ( a || b ) {
1617 // different count
1618 return false;
1619 }
1620 return true;
1621 }
1622 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001623}
1624
1625
Lee Thomason751da522012-02-10 08:50:51 -08001626bool XMLElement::Accept( XMLVisitor* visitor ) const
1627{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001628 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1631 if ( !node->Accept( visitor ) ) {
1632 break;
1633 }
1634 }
1635 }
1636 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001637}
Lee Thomason56bdd022012-02-09 18:16:58 -08001638
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001639
Lee Thomason3f57d272012-01-11 15:30:03 -08001640// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001641
1642// Warning: List must match 'enum XMLError'
1643const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1644 "XML_SUCCESS",
1645 "XML_NO_ATTRIBUTE",
1646 "XML_WRONG_ATTRIBUTE_TYPE",
1647 "XML_ERROR_FILE_NOT_FOUND",
1648 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1649 "XML_ERROR_FILE_READ_ERROR",
1650 "XML_ERROR_ELEMENT_MISMATCH",
1651 "XML_ERROR_PARSING_ELEMENT",
1652 "XML_ERROR_PARSING_ATTRIBUTE",
1653 "XML_ERROR_IDENTIFYING_TAG",
1654 "XML_ERROR_PARSING_TEXT",
1655 "XML_ERROR_PARSING_CDATA",
1656 "XML_ERROR_PARSING_COMMENT",
1657 "XML_ERROR_PARSING_DECLARATION",
1658 "XML_ERROR_PARSING_UNKNOWN",
1659 "XML_ERROR_EMPTY_DOCUMENT",
1660 "XML_ERROR_MISMATCHED_ELEMENT",
1661 "XML_ERROR_PARSING",
1662 "XML_CAN_NOT_CONVERT_TEXT",
1663 "XML_NO_TEXT_NODE"
1664};
1665
1666
Lee Thomason624d43f2012-10-12 10:58:48 -07001667XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _writeBOM( false ),
1670 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001671 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 _whitespace( whitespace ),
1673 _errorStr1( 0 ),
1674 _errorStr2( 0 ),
1675 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001676{
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001678}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001679
1680
Lee Thomason3f57d272012-01-11 15:30:03 -08001681XMLDocument::~XMLDocument()
1682{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001683 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001684}
1685
1686
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001687void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001688{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001689 DeleteChildren();
1690
Dmitry-Meab37df82014-11-28 12:08:36 +03001691#ifdef DEBUG
1692 const bool hadError = Error();
1693#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 _errorID = XML_NO_ERROR;
1695 _errorStr1 = 0;
1696 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001697
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 delete [] _charBuffer;
1699 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001700
1701#if 0
1702 _textPool.Trace( "text" );
1703 _elementPool.Trace( "element" );
1704 _commentPool.Trace( "comment" );
1705 _attributePool.Trace( "attribute" );
1706#endif
1707
1708#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001709 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001710 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1711 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1712 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1713 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1714 }
1715#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001716}
1717
Lee Thomason3f57d272012-01-11 15:30:03 -08001718
Lee Thomason2c85a712012-01-31 08:24:24 -08001719XMLElement* XMLDocument::NewElement( const char* name )
1720{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001721 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1723 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 ele->SetName( name );
1725 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001726}
1727
1728
Lee Thomason1ff38e02012-02-14 18:18:16 -08001729XMLComment* XMLDocument::NewComment( const char* str )
1730{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001731 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1733 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 comment->SetValue( str );
1735 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001736}
1737
1738
1739XMLText* XMLDocument::NewText( const char* str )
1740{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001741 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1743 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 text->SetValue( str );
1745 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001746}
1747
1748
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1750{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001751 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1753 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1755 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001756}
1757
1758
1759XMLUnknown* XMLDocument::NewUnknown( const char* str )
1760{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001761 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1763 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 unk->SetValue( str );
1765 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766}
1767
Dmitry-Me01578db2014-08-19 10:18:48 +04001768static FILE* callfopen( const char* filepath, const char* mode )
1769{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001770 TIXMLASSERT( filepath );
1771 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001772#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1773 FILE* fp = 0;
1774 errno_t err = fopen_s( &fp, filepath, mode );
1775 if ( err ) {
1776 return 0;
1777 }
1778#else
1779 FILE* fp = fopen( filepath, mode );
1780#endif
1781 return fp;
1782}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001783
1784void XMLDocument::DeleteNode( XMLNode* node ) {
1785 TIXMLASSERT( node );
1786 TIXMLASSERT(node->_document == this );
1787 if (node->_parent) {
1788 node->_parent->DeleteChild( node );
1789 }
1790 else {
1791 // Isn't in the tree.
1792 // Use the parent delete.
1793 // Also, we need to mark it tracked: we 'know'
1794 // it was never used.
1795 node->_memPool->SetTracked();
1796 // Call the static XMLNode version:
1797 XMLNode::DeleteNode(node);
1798 }
1799}
1800
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001801
Lee Thomason2fa81722012-11-09 12:37:46 -08001802XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001803{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001804 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001805 FILE* fp = callfopen( filename, "rb" );
1806 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 }
1810 LoadFile( fp );
1811 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001813}
1814
1815
Lee Thomason2fa81722012-11-09 12:37:46 -08001816XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001817{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001818 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001819
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001820 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001821 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001822 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1823 return _errorID;
1824 }
1825
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001827 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001829 if ( filelength == -1L ) {
1830 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1831 return _errorID;
1832 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001834 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001836 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001839
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _charBuffer = new char[size+1];
1841 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 if ( read != size ) {
1843 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001846
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848
Dmitry-Me97476b72015-01-01 16:15:57 +03001849 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001851}
1852
1853
Lee Thomason2fa81722012-11-09 12:37:46 -08001854XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001855{
Dmitry-Me01578db2014-08-19 10:18:48 +04001856 FILE* fp = callfopen( filename, "w" );
1857 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
1861 SaveFile(fp, compact);
1862 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001864}
1865
1866
Lee Thomason2fa81722012-11-09 12:37:46 -08001867XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001868{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 XMLPrinter stream( fp, compact );
1870 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001872}
1873
Lee Thomason1ff38e02012-02-14 18:18:16 -08001874
Lee Thomason2fa81722012-11-09 12:37:46 -08001875XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001876{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001877 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001878
Lee Thomason82d32002014-02-21 22:47:18 -08001879 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 }
1883 if ( len == (size_t)(-1) ) {
1884 len = strlen( p );
1885 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 _charBuffer = new char[ len+1 ];
1887 memcpy( _charBuffer, p, len );
1888 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001889
Dmitry-Me97476b72015-01-01 16:15:57 +03001890 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001891 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001892 // clean up now essentially dangling memory.
1893 // and the parse fail can put objects in the
1894 // pools that are dead and inaccessible.
1895 DeleteChildren();
1896 _elementPool.Clear();
1897 _attributePool.Clear();
1898 _textPool.Clear();
1899 _commentPool.Clear();
1900 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001902}
1903
1904
PKEuS1c5f99e2013-07-06 11:28:39 +02001905void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 XMLPrinter stdStreamer( stdout );
1908 if ( !streamer ) {
1909 streamer = &stdStreamer;
1910 }
1911 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001912}
1913
1914
Lee Thomason2fa81722012-11-09 12:37:46 -08001915void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001916{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001917 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 _errorID = error;
1919 _errorStr1 = str1;
1920 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001921}
1922
Lee Thomason331596e2014-09-11 14:56:43 -07001923const char* XMLDocument::ErrorName() const
1924{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001925 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001926 return _errorNames[_errorID];
1927}
Lee Thomason5cae8972012-01-24 18:03:07 -08001928
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001929void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001930{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001931 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 static const int LEN = 20;
1933 char buf1[LEN] = { 0 };
1934 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001935
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 if ( _errorStr1 ) {
1937 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 if ( _errorStr2 ) {
1940 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001942
Lee Thomason331596e2014-09-11 14:56:43 -07001943 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1944 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001946}
1947
Dmitry-Me97476b72015-01-01 16:15:57 +03001948void XMLDocument::Parse()
1949{
1950 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1951 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001952 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001953 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001954 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001955 if ( !*p ) {
1956 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1957 return;
1958 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001959 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001960}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001961
PKEuS1bfb9542013-08-04 13:51:17 +02001962XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 _elementJustOpened( false ),
1964 _firstElement( true ),
1965 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001966 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 _textDepth( -1 ),
1968 _processEntities( true ),
1969 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 _entityFlag[i] = false;
1973 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 }
1975 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001976 const char entityValue = entities[i].value;
1977 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1978 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001980 _restrictedEntityFlag[(unsigned char)'&'] = true;
1981 _restrictedEntityFlag[(unsigned char)'<'] = true;
1982 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001983 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001984}
1985
1986
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001987void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001988{
1989 va_list va;
1990 va_start( va, format );
1991
Lee Thomason624d43f2012-10-12 10:58:48 -07001992 if ( _fp ) {
1993 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 }
1995 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001996#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001997 #if defined(WINCE)
1998 int len = 512;
1999 do {
2000 len = len*2;
2001 char* str = new char[len]();
2002 len = _vsnprintf(str, len, format, va);
2003 delete[] str;
2004 }while (len < 0);
2005 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002006 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002007 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008#else
2009 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002010#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 // Close out and re-start the va-args
2012 va_end( va );
2013 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002014 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002015 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2016#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002017 #if defined(WINCE)
2018 _vsnprintf( p, len+1, format, va );
2019 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002020 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002021 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002022#else
2023 vsnprintf( p, len+1, format, va );
2024#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002026 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002027}
2028
2029
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002030void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 for( int i=0; i<depth; ++i ) {
2033 Print( " " );
2034 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002035}
2036
2037
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002038void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 // Look for runs of bytes between entities to print.
2041 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002042
Lee Thomason624d43f2012-10-12 10:58:48 -07002043 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002044 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 while ( *q ) {
2046 // Remember, char is sometimes signed. (How many times has that bitten me?)
2047 if ( *q > 0 && *q < ENTITY_RANGE ) {
2048 // Check for entities. If one is found, flush
2049 // the stream up until the entity, write the
2050 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002051 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 while ( p < q ) {
2053 Print( "%c", *p );
2054 ++p;
2055 }
2056 for( int i=0; i<NUM_ENTITIES; ++i ) {
2057 if ( entities[i].value == *q ) {
2058 Print( "&%s;", entities[i].pattern );
2059 break;
2060 }
2061 }
2062 ++p;
2063 }
2064 }
2065 ++q;
2066 }
2067 }
2068 // Flush the remaining string. This will be the entire
2069 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 Print( "%s", p );
2072 }
Lee Thomason857b8682012-01-25 17:50:25 -08002073}
2074
U-Stream\Leeae25a442012-02-17 17:48:16 -08002075
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002076void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002079 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 -07002080 Print( "%s", bom );
2081 }
2082 if ( writeDec ) {
2083 PushDeclaration( "xml version=\"1.0\"" );
2084 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002085}
2086
2087
Uli Kusterer593a33d2014-02-01 12:48:51 +01002088void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002089{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002090 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002092
Uli Kusterer593a33d2014-02-01 12:48:51 +01002093 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002095 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002096 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002097 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002099
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002101 _elementJustOpened = true;
2102 _firstElement = false;
2103 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002104}
2105
2106
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002107void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002108{
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 Print( " %s=\"", name );
2111 PrintString( value, false );
2112 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002113}
2114
2115
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002116void XMLPrinter::PushAttribute( const char* name, int 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, unsigned 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, bool 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
2140void XMLPrinter::PushAttribute( const char* name, double v )
2141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 char buf[BUF_SIZE];
2143 XMLUtil::ToStr( v, buf, BUF_SIZE );
2144 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002145}
2146
2147
Uli Kustererca412e82014-02-01 13:35:05 +01002148void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002149{
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 --_depth;
2151 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002152
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 Print( "/>" );
2155 }
2156 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002157 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 }
2161 Print( "</%s>", name );
2162 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002163
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 if ( _textDepth == _depth ) {
2165 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 }
Uli Kustererca412e82014-02-01 13:35:05 +01002167 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 Print( "\n" );
2169 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002171}
2172
2173
Dmitry-Mea092bc12014-12-23 17:57:05 +03002174void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002175{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002176 if ( !_elementJustOpened ) {
2177 return;
2178 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002181}
2182
2183
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002184void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002185{
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002187
Dmitry-Mea092bc12014-12-23 17:57:05 +03002188 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 if ( cdata ) {
2190 Print( "<![CDATA[" );
2191 Print( "%s", text );
2192 Print( "]]>" );
2193 }
2194 else {
2195 PrintString( text, true );
2196 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002197}
2198
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002199void XMLPrinter::PushText( int 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( unsigned 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( bool 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( float 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
2230
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002231void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 char buf[BUF_SIZE];
2234 XMLUtil::ToStr( value, buf, BUF_SIZE );
2235 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002236}
2237
Lee Thomason5cae8972012-01-24 18:03:07 -08002238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002240{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002241 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002248}
Lee Thomason751da522012-02-10 08:50:51 -08002249
2250
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002251void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002252{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002253 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002260}
2261
2262
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002263void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002264{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002265 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002266 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002268 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002272}
2273
2274
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002275bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002276{
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 if ( doc.HasBOM() ) {
2279 PushHeader( true, false );
2280 }
2281 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002282}
2283
2284
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002285bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002286{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002287 const XMLElement* parentElem = element.Parent()->ToElement();
2288 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2289 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 while ( attribute ) {
2291 PushAttribute( attribute->Name(), attribute->Value() );
2292 attribute = attribute->Next();
2293 }
2294 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002295}
2296
2297
Uli Kustererca412e82014-02-01 13:35:05 +01002298bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002299{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002300 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002302}
2303
2304
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002305bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 PushText( text.Value(), text.CData() );
2308 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002309}
2310
2311
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002312bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002314 PushComment( comment.Value() );
2315 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002316}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 PushDeclaration( declaration.Value() );
2321 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322}
2323
2324
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002325bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 PushUnknown( unknown.Value() );
2328 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002329}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002330
Lee Thomason685b8952012-11-12 13:00:06 -08002331} // namespace tinyxml2
2332