blob: 5b32f40b4cc734b2d4eb7d15e07f034207a2dee7 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300342 default:
343 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345}
346
347
348const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700350 // Presume an entity, and pull it out.
351 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 if ( *(p+1) == '#' && *(p+2) ) {
354 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300355 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 ptrdiff_t delta = 0;
357 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800358 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( *(p+2) == 'x' ) {
361 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300362 const char* q = p+3;
363 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 return 0;
365 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomason7e67bc82015-01-12 14:05:12 -0800367 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Dmitry-Me9f56e122015-01-12 10:07:54 +0300369 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 return 0;
371 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800372 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800373
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700374 delta = q-p;
375 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800376
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 while ( *q != 'x' ) {
378 if ( *q >= '0' && *q <= '9' ) {
379 ucs += mult * (*q - '0');
380 }
381 else if ( *q >= 'a' && *q <= 'f' ) {
382 ucs += mult * (*q - 'a' + 10);
383 }
384 else if ( *q >= 'A' && *q <= 'F' ) {
385 ucs += mult * (*q - 'A' + 10 );
386 }
387 else {
388 return 0;
389 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300390 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 mult *= 16;
392 --q;
393 }
394 }
395 else {
396 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300397 const char* q = p+2;
398 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return 0;
400 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800401
Lee Thomason7e67bc82015-01-12 14:05:12 -0800402 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403
Dmitry-Me9f56e122015-01-12 10:07:54 +0300404 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 return 0;
406 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800407 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 delta = q-p;
410 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800411
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 while ( *q != '#' ) {
413 if ( *q >= '0' && *q <= '9' ) {
414 ucs += mult * (*q - '0');
415 }
416 else {
417 return 0;
418 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300419 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700420 mult *= 10;
421 --q;
422 }
423 }
424 // convert the UCS to UTF-8
425 ConvertUTF32ToUTF8( ucs, value, length );
426 return p + delta + 1;
427 }
428 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800429}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800430
431
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700432void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700433{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700435}
436
437
438void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700441}
442
443
444void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800449/*
450 ToStr() of a number is a very tricky topic.
451 https://github.com/leethomason/tinyxml2/issues/106
452*/
Lee Thomason21be8822012-07-15 17:27:22 -0700453void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
454{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800455 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700456}
457
458
459void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
460{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800461 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700462}
463
464
465bool XMLUtil::ToInt( const char* str, int* value )
466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
468 return true;
469 }
470 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700471}
472
473bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
476 return true;
477 }
478 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700479}
480
481bool XMLUtil::ToBool( const char* str, bool* value )
482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 int ival = 0;
484 if ( ToInt( str, &ival )) {
485 *value = (ival==0) ? false : true;
486 return true;
487 }
488 if ( StringEqual( str, "true" ) ) {
489 *value = true;
490 return true;
491 }
492 else if ( StringEqual( str, "false" ) ) {
493 *value = false;
494 return true;
495 }
496 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700497}
498
499
500bool XMLUtil::ToFloat( const char* str, float* value )
501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
503 return true;
504 }
505 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700506}
507
508bool XMLUtil::ToDouble( const char* str, double* value )
509{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
511 return true;
512 }
513 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700514}
515
516
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700517char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800518{
Dmitry-Me02384662015-03-03 16:02:13 +0300519 TIXMLASSERT( node );
520 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400521 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300523 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300524 *node = 0;
525 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 return p;
527 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800530 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 static const char* xmlHeader = { "<?" };
532 static const char* commentHeader = { "<!--" };
533 static const char* dtdHeader = { "<!" };
534 static const char* cdataHeader = { "<![CDATA[" };
535 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800536
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 static const int xmlHeaderLen = 2;
538 static const int commentHeaderLen = 4;
539 static const int dtdHeaderLen = 2;
540 static const int cdataHeaderLen = 9;
541 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800542
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
544 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400545 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300547 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
549 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += xmlHeaderLen;
551 }
552 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300553 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLComment( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += commentHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300559 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700562 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 p += cdataHeaderLen;
564 text->SetCData( true );
565 }
566 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300567 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700568 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
569 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 p += dtdHeaderLen;
571 }
572 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300573 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700574 returnNode = new (_elementPool.Alloc()) XMLElement( this );
575 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 p += elementHeaderLen;
577 }
578 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300579 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 returnNode = new (_textPool.Alloc()) XMLText( this );
581 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 p = start; // Back it up, all the text counts.
583 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800584
Dmitry-Me02384662015-03-03 16:02:13 +0300585 TIXMLASSERT( returnNode );
586 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700587 *node = returnNode;
588 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800589}
590
591
Lee Thomason751da522012-02-10 08:50:51 -0800592bool XMLDocument::Accept( XMLVisitor* visitor ) const
593{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300594 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 if ( visitor->VisitEnter( *this ) ) {
596 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
597 if ( !node->Accept( visitor ) ) {
598 break;
599 }
600 }
601 }
602 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800603}
Lee Thomason56bdd022012-02-09 18:16:58 -0800604
605
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800606// --------- XMLNode ----------- //
607
608XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 _document( doc ),
610 _parent( 0 ),
611 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200612 _prev( 0 ), _next( 0 ),
613 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800614{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800615}
616
617
618XMLNode::~XMLNode()
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 if ( _parent ) {
622 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800624}
625
Michael Daumling21626882013-10-22 17:03:37 +0200626const char* XMLNode::Value() const
627{
628 return _value.GetStr();
629}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800630
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800631void XMLNode::SetValue( const char* str, bool staticMem )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 }
636 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800639}
640
641
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800642void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800643{
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300645 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700648
Dmitry-Mee3225b12014-09-03 11:03:11 +0400649 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800652}
653
654
655void XMLNode::Unlink( XMLNode* child )
656{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300657 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300658 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( child == _firstChild ) {
660 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 if ( child == _lastChild ) {
663 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 }
Lee Thomasond923c672012-01-23 08:44:25 -0800665
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 if ( child->_prev ) {
667 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 if ( child->_next ) {
670 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700672 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673}
674
675
U-Stream\Leeae25a442012-02-17 17:48:16 -0800676void XMLNode::DeleteChild( XMLNode* node )
677{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300678 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300679 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400681 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800682}
683
684
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800685XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
686{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300687 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300688 if ( addThis->_document != _document ) {
689 TIXMLASSERT( false );
690 return 0;
691 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800692 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 if ( _lastChild ) {
695 TIXMLASSERT( _firstChild );
696 TIXMLASSERT( _lastChild->_next == 0 );
697 _lastChild->_next = addThis;
698 addThis->_prev = _lastChild;
699 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800700
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
703 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 TIXMLASSERT( _firstChild == 0 );
705 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 addThis->_prev = 0;
708 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800712}
713
714
Lee Thomason1ff38e02012-02-14 18:18:16 -0800715XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
716{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300717 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300718 if ( addThis->_document != _document ) {
719 TIXMLASSERT( false );
720 return 0;
721 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800722 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 if ( _firstChild ) {
725 TIXMLASSERT( _lastChild );
726 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800727
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 _firstChild->_prev = addThis;
729 addThis->_next = _firstChild;
730 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
734 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 TIXMLASSERT( _lastChild == 0 );
736 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 addThis->_prev = 0;
739 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400742 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800743}
744
745
746XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
747{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( addThis );
749 if ( addThis->_document != _document ) {
750 TIXMLASSERT( false );
751 return 0;
752 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700753
Dmitry-Meabb2d042014-12-09 12:59:31 +0300754 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700755
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300757 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 return 0;
759 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800760
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 // The last node or the only node.
763 return InsertEndChild( addThis );
764 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800765 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700766 addThis->_prev = afterThis;
767 addThis->_next = afterThis->_next;
768 afterThis->_next->_prev = addThis;
769 afterThis->_next = addThis;
770 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800772}
773
774
775
776
Lee Thomason56bdd022012-02-09 18:16:58 -0800777const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800778{
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 XMLElement* element = node->ToElement();
781 if ( element ) {
782 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
783 return element;
784 }
785 }
786 }
787 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800788}
789
790
Lee Thomason56bdd022012-02-09 18:16:58 -0800791const XMLElement* XMLNode::LastChildElement( const char* value ) const
792{
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 XMLElement* element = node->ToElement();
795 if ( element ) {
796 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
797 return element;
798 }
799 }
800 }
801 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800802}
803
804
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800805const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
806{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400807 for( XMLNode* node=this->_next; node; node = node->_next ) {
808 const XMLElement* element = node->ToElement();
809 if ( element
810 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
811 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 }
813 }
814 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800815}
816
817
818const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
819{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400820 for( XMLNode* node=_prev; node; node = node->_prev ) {
821 const XMLElement* element = node->ToElement();
822 if ( element
823 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
824 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 }
826 }
827 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800828}
829
830
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800831char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800832{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // This is a recursive method, but thinking about it "at the current level"
834 // it is a pretty simple flat list:
835 // <foo/>
836 // <!-- comment -->
837 //
838 // With a special case:
839 // <foo>
840 // </foo>
841 // <!-- comment -->
842 //
843 // Where the closing element (/foo) *must* be the next thing after the opening
844 // element, and the names must match. BUT the tricky bit is that the closing
845 // element will be read by the child.
846 //
847 // 'endTag' is the end tag for this node, it is returned by a call to a child.
848 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800849
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 while( p && *p ) {
851 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800852
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300854 if ( node == 0 ) {
855 break;
856 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800857
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 StrPair endTag;
859 p = node->ParseDeep( p, &endTag );
860 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400861 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 if ( !_document->Error() ) {
863 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
865 break;
866 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800867
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400868 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500870 // We read the end tag. Return it to the parent.
871 if ( ele->ClosingType() == XMLElement::CLOSING ) {
872 if ( parentEnd ) {
873 ele->_value.TransferTo( parentEnd );
874 }
875 node->_memPool->SetTracked(); // created and then immediately deleted.
876 DeleteNode( node );
877 return p;
878 }
879
880 // Handle an end tag returned to this level.
881 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400882 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300883 if ( endTag.Empty() ) {
884 if ( ele->ClosingType() == XMLElement::OPEN ) {
885 mismatch = true;
886 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300888 else {
889 if ( ele->ClosingType() != XMLElement::OPEN ) {
890 mismatch = true;
891 }
892 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400893 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
895 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400896 if ( mismatch ) {
897 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500898 DeleteNode( node );
899 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400900 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 }
JayXondbfdd8f2014-12-12 20:07:14 -0500902 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800905}
906
Dmitry-Mee3225b12014-09-03 11:03:11 +0400907void XMLNode::DeleteNode( XMLNode* node )
908{
909 if ( node == 0 ) {
910 return;
911 }
912 MemPool* pool = node->_memPool;
913 node->~XMLNode();
914 pool->Free( node );
915}
916
Lee Thomason3cebdc42015-01-05 17:16:28 -0800917void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300918{
919 TIXMLASSERT( insertThis );
920 TIXMLASSERT( insertThis->_document == _document );
921
922 if ( insertThis->_parent )
923 insertThis->_parent->Unlink( insertThis );
924 else
925 insertThis->_memPool->SetTracked();
926}
927
Lee Thomason5492a1c2012-01-23 15:32:10 -0800928// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800929char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800930{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 const char* start = p;
932 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700933 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700935 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 }
937 return p;
938 }
939 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
941 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 flags |= StrPair::COLLAPSE_WHITESPACE;
943 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700944
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 if ( p && *p ) {
947 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300948 }
949 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300950 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 }
952 }
953 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800954}
955
956
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
958{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700960 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 }
962 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
963 text->SetCData( this->CData() );
964 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965}
966
967
968bool XMLText::ShallowEqual( const XMLNode* compare ) const
969{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400970 const XMLText* text = compare->ToText();
971 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Lee Thomason56bdd022012-02-09 18:16:58 -0800975bool XMLText::Accept( XMLVisitor* visitor ) const
976{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300977 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800979}
980
981
Lee Thomason3f57d272012-01-11 15:30:03 -0800982// --------- XMLComment ---------- //
983
Lee Thomasone4422302012-01-20 17:59:50 -0800984XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800985{
986}
987
988
Lee Thomasonce0763e2012-01-11 15:43:54 -0800989XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800990{
Lee Thomason3f57d272012-01-11 15:30:03 -0800991}
992
993
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800994char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 // Comment parses as text.
997 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001000 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 }
1002 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001003}
1004
1005
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001006XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 }
1011 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1012 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001013}
1014
1015
1016bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1017{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001018 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001019 const XMLComment* comment = compare->ToComment();
1020 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001021}
1022
1023
Lee Thomason751da522012-02-10 08:50:51 -08001024bool XMLComment::Accept( XMLVisitor* visitor ) const
1025{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001026 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001028}
Lee Thomason56bdd022012-02-09 18:16:58 -08001029
1030
Lee Thomason50f97b22012-02-11 16:33:40 -08001031// --------- XMLDeclaration ---------- //
1032
1033XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1034{
1035}
1036
1037
1038XMLDeclaration::~XMLDeclaration()
1039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001044char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 // Declaration parses as text.
1047 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 }
1052 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001053}
1054
1055
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001056XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001059 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 }
1061 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1062 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001063}
1064
1065
1066bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1067{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001068 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001069 const XMLDeclaration* declaration = compare->ToDeclaration();
1070 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001071}
1072
1073
1074
Lee Thomason50f97b22012-02-11 16:33:40 -08001075bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1076{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001077 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001079}
1080
1081// --------- XMLUnknown ---------- //
1082
1083XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1084{
1085}
1086
1087
1088XMLUnknown::~XMLUnknown()
1089{
1090}
1091
1092
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001093char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 // Unknown parses as text.
1096 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001097
Lee Thomason624d43f2012-10-12 10:58:48 -07001098 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001100 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 }
1102 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001103}
1104
1105
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001106XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001109 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 }
1111 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1112 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001113}
1114
1115
1116bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1117{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001118 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001119 const XMLUnknown* unknown = compare->ToUnknown();
1120 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001121}
1122
1123
Lee Thomason50f97b22012-02-11 16:33:40 -08001124bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1125{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001126 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001128}
1129
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001130// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001131
1132const char* XMLAttribute::Name() const
1133{
1134 return _name.GetStr();
1135}
1136
1137const char* XMLAttribute::Value() const
1138{
1139 return _value.GetStr();
1140}
1141
Lee Thomason6f381b72012-03-02 12:59:39 -08001142char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001145 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 if ( !p || !*p ) {
1147 return 0;
1148 }
Lee Thomason22aead12012-01-23 13:29:35 -08001149
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 // Skip white space before =
1151 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001152 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 return 0;
1154 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001155
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 ++p; // move up to opening quote
1157 p = XMLUtil::SkipWhiteSpace( p );
1158 if ( *p != '\"' && *p != '\'' ) {
1159 return 0;
1160 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001161
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 char endTag[2] = { *p, 0 };
1163 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001164
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001167}
1168
1169
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001170void XMLAttribute::SetName( const char* n )
1171{
Lee Thomason624d43f2012-10-12 10:58:48 -07001172 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001173}
1174
1175
Lee Thomason2fa81722012-11-09 12:37:46 -08001176XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 if ( XMLUtil::ToInt( Value(), value )) {
1179 return XML_NO_ERROR;
1180 }
1181 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001182}
1183
1184
Lee Thomason2fa81722012-11-09 12:37:46 -08001185XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 if ( XMLUtil::ToUnsigned( Value(), value )) {
1188 return XML_NO_ERROR;
1189 }
1190 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001191}
1192
1193
Lee Thomason2fa81722012-11-09 12:37:46 -08001194XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 if ( XMLUtil::ToBool( Value(), value )) {
1197 return XML_NO_ERROR;
1198 }
1199 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001200}
1201
1202
Lee Thomason2fa81722012-11-09 12:37:46 -08001203XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 if ( XMLUtil::ToFloat( Value(), value )) {
1206 return XML_NO_ERROR;
1207 }
1208 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001209}
1210
1211
Lee Thomason2fa81722012-11-09 12:37:46 -08001212XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 if ( XMLUtil::ToDouble( Value(), value )) {
1215 return XML_NO_ERROR;
1216 }
1217 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218}
1219
1220
1221void XMLAttribute::SetAttribute( const char* v )
1222{
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001224}
1225
1226
Lee Thomason1ff38e02012-02-14 18:18:16 -08001227void XMLAttribute::SetAttribute( int v )
1228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 char buf[BUF_SIZE];
1230 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001232}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001233
1234
1235void XMLAttribute::SetAttribute( unsigned v )
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 char buf[BUF_SIZE];
1238 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242
1243void XMLAttribute::SetAttribute( bool v )
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 char buf[BUF_SIZE];
1246 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
1250void XMLAttribute::SetAttribute( double 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( float 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
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001264
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001265// --------- XMLElement ---------- //
1266XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _closingType( 0 ),
1268 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269{
1270}
1271
1272
1273XMLElement::~XMLElement()
1274{
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 while( _rootAttribute ) {
1276 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001277 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001278 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001280}
1281
1282
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001283const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1284{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001285 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1287 return a;
1288 }
1289 }
1290 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001291}
1292
1293
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001294const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 const XMLAttribute* a = FindAttribute( name );
1297 if ( !a ) {
1298 return 0;
1299 }
1300 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1301 return a->Value();
1302 }
1303 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001304}
1305
1306
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001307const char* XMLElement::GetText() const
1308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001310 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 }
1312 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001313}
1314
1315
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001316void XMLElement::SetText( const char* inText )
1317{
Uli Kusterer869bb592014-01-21 01:36:16 +01001318 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001319 FirstChild()->SetValue( inText );
1320 else {
1321 XMLText* theText = GetDocument()->NewText( inText );
1322 InsertFirstChild( theText );
1323 }
1324}
1325
Lee Thomason5bb2d802014-01-24 10:42:57 -08001326
1327void XMLElement::SetText( int v )
1328{
1329 char buf[BUF_SIZE];
1330 XMLUtil::ToStr( v, buf, BUF_SIZE );
1331 SetText( buf );
1332}
1333
1334
1335void XMLElement::SetText( unsigned v )
1336{
1337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( v, buf, BUF_SIZE );
1339 SetText( buf );
1340}
1341
1342
1343void XMLElement::SetText( bool v )
1344{
1345 char buf[BUF_SIZE];
1346 XMLUtil::ToStr( v, buf, BUF_SIZE );
1347 SetText( buf );
1348}
1349
1350
1351void XMLElement::SetText( float v )
1352{
1353 char buf[BUF_SIZE];
1354 XMLUtil::ToStr( v, buf, BUF_SIZE );
1355 SetText( buf );
1356}
1357
1358
1359void XMLElement::SetText( double v )
1360{
1361 char buf[BUF_SIZE];
1362 XMLUtil::ToStr( v, buf, BUF_SIZE );
1363 SetText( buf );
1364}
1365
1366
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001370 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001371 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 return XML_SUCCESS;
1373 }
1374 return XML_CAN_NOT_CONVERT_TEXT;
1375 }
1376 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001377}
1378
1379
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001383 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001384 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 return XML_SUCCESS;
1386 }
1387 return XML_CAN_NOT_CONVERT_TEXT;
1388 }
1389 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001390}
1391
1392
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001394{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001396 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001397 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 return XML_SUCCESS;
1399 }
1400 return XML_CAN_NOT_CONVERT_TEXT;
1401 }
1402 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001403}
1404
1405
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001409 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001410 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 return XML_SUCCESS;
1412 }
1413 return XML_CAN_NOT_CONVERT_TEXT;
1414 }
1415 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001416}
1417
1418
MortenMacFly4ee49f12013-01-14 20:03:14 +01001419XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001422 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001423 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 return XML_SUCCESS;
1425 }
1426 return XML_CAN_NOT_CONVERT_TEXT;
1427 }
1428 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001429}
1430
1431
1432
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001433XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 XMLAttribute* last = 0;
1436 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1441 break;
1442 }
1443 }
1444 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001445 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1447 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
1451 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 }
1454 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001455 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 }
1457 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458}
1459
1460
U-Stream\Leeae25a442012-02-17 17:48:16 -08001461void XMLElement::DeleteAttribute( const char* name )
1462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1466 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001467 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 }
1469 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001472 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 break;
1474 }
1475 prev = a;
1476 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001477}
1478
1479
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001480char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 const char* start = p;
1483 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001484
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 // Read the attributes.
1486 while( p ) {
1487 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001488 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 return 0;
1491 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001492
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001494 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001495 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1497 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001498 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001499
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001502 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 return 0;
1505 }
1506 // There is a minor bug here: if the attribute in the source xml
1507 // document is duplicated, it will not be detected and the
1508 // attribute will be doubly added. However, tracking the 'prevAttribute'
1509 // avoids re-scanning the attribute list. Preferring performance for
1510 // now, may reconsider in the future.
1511 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 }
1514 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 }
1517 prevAttribute = attrib;
1518 }
1519 // end of the tag
1520 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001521 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 return p+2; // done; sealed element.
1523 }
1524 // end of the tag
1525 else if ( *p == '>' ) {
1526 ++p;
1527 break;
1528 }
1529 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 return 0;
1532 }
1533 }
1534 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001535}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001536
Dmitry-Mee3225b12014-09-03 11:03:11 +04001537void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1538{
1539 if ( attribute == 0 ) {
1540 return;
1541 }
1542 MemPool* pool = attribute->_memPool;
1543 attribute->~XMLAttribute();
1544 pool->Free( attribute );
1545}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001546
Lee Thomason67d61312012-01-24 16:01:51 -08001547//
1548// <ele></ele>
1549// <ele>foo<b>bar</b></ele>
1550//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001551char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 // Read the element name.
1554 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001555
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 // The closing element is the </element> form. It is
1557 // parsed just like a regular element then deleted from
1558 // the DOM.
1559 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 ++p;
1562 }
Lee Thomason67d61312012-01-24 16:01:51 -08001563
Lee Thomason624d43f2012-10-12 10:58:48 -07001564 p = _value.ParseName( p );
1565 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 return 0;
1567 }
Lee Thomason67d61312012-01-24 16:01:51 -08001568
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 return p;
1572 }
Lee Thomason67d61312012-01-24 16:01:51 -08001573
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 p = XMLNode::ParseDeep( p, strPair );
1575 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001576}
1577
1578
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579
1580XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001583 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 }
1585 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1586 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1587 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1588 }
1589 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590}
1591
1592
1593bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1594{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001595 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 const XMLElement* other = compare->ToElement();
1597 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001598
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 const XMLAttribute* a=FirstAttribute();
1600 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001601
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 while ( a && b ) {
1603 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1604 return false;
1605 }
1606 a = a->Next();
1607 b = b->Next();
1608 }
1609 if ( a || b ) {
1610 // different count
1611 return false;
1612 }
1613 return true;
1614 }
1615 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616}
1617
1618
Lee Thomason751da522012-02-10 08:50:51 -08001619bool XMLElement::Accept( XMLVisitor* visitor ) const
1620{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001621 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1624 if ( !node->Accept( visitor ) ) {
1625 break;
1626 }
1627 }
1628 }
1629 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001630}
Lee Thomason56bdd022012-02-09 18:16:58 -08001631
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001632
Lee Thomason3f57d272012-01-11 15:30:03 -08001633// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001634
1635// Warning: List must match 'enum XMLError'
1636const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1637 "XML_SUCCESS",
1638 "XML_NO_ATTRIBUTE",
1639 "XML_WRONG_ATTRIBUTE_TYPE",
1640 "XML_ERROR_FILE_NOT_FOUND",
1641 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1642 "XML_ERROR_FILE_READ_ERROR",
1643 "XML_ERROR_ELEMENT_MISMATCH",
1644 "XML_ERROR_PARSING_ELEMENT",
1645 "XML_ERROR_PARSING_ATTRIBUTE",
1646 "XML_ERROR_IDENTIFYING_TAG",
1647 "XML_ERROR_PARSING_TEXT",
1648 "XML_ERROR_PARSING_CDATA",
1649 "XML_ERROR_PARSING_COMMENT",
1650 "XML_ERROR_PARSING_DECLARATION",
1651 "XML_ERROR_PARSING_UNKNOWN",
1652 "XML_ERROR_EMPTY_DOCUMENT",
1653 "XML_ERROR_MISMATCHED_ELEMENT",
1654 "XML_ERROR_PARSING",
1655 "XML_CAN_NOT_CONVERT_TEXT",
1656 "XML_NO_TEXT_NODE"
1657};
1658
1659
Lee Thomason624d43f2012-10-12 10:58:48 -07001660XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 _writeBOM( false ),
1663 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001664 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001665 _whitespace( whitespace ),
1666 _errorStr1( 0 ),
1667 _errorStr2( 0 ),
1668 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001671}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001672
1673
Lee Thomason3f57d272012-01-11 15:30:03 -08001674XMLDocument::~XMLDocument()
1675{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001676 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001677}
1678
1679
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001680void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001681{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001682 DeleteChildren();
1683
Dmitry-Meab37df82014-11-28 12:08:36 +03001684#ifdef DEBUG
1685 const bool hadError = Error();
1686#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 _errorID = XML_NO_ERROR;
1688 _errorStr1 = 0;
1689 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001690
Lee Thomason624d43f2012-10-12 10:58:48 -07001691 delete [] _charBuffer;
1692 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001693
1694#if 0
1695 _textPool.Trace( "text" );
1696 _elementPool.Trace( "element" );
1697 _commentPool.Trace( "comment" );
1698 _attributePool.Trace( "attribute" );
1699#endif
1700
1701#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001702 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001703 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1704 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1705 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1706 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1707 }
1708#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001709}
1710
Lee Thomason3f57d272012-01-11 15:30:03 -08001711
Lee Thomason2c85a712012-01-31 08:24:24 -08001712XMLElement* XMLDocument::NewElement( const char* name )
1713{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001714 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1716 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 ele->SetName( name );
1718 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001719}
1720
1721
Lee Thomason1ff38e02012-02-14 18:18:16 -08001722XMLComment* XMLDocument::NewComment( const char* str )
1723{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001724 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1726 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 comment->SetValue( str );
1728 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001729}
1730
1731
1732XMLText* XMLDocument::NewText( const char* str )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1736 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 text->SetValue( str );
1738 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001739}
1740
1741
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001742XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1743{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001744 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1746 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1748 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749}
1750
1751
1752XMLUnknown* XMLDocument::NewUnknown( const char* str )
1753{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001754 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1756 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 unk->SetValue( str );
1758 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001759}
1760
Dmitry-Me01578db2014-08-19 10:18:48 +04001761static FILE* callfopen( const char* filepath, const char* mode )
1762{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001763 TIXMLASSERT( filepath );
1764 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001765#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1766 FILE* fp = 0;
1767 errno_t err = fopen_s( &fp, filepath, mode );
1768 if ( err ) {
1769 return 0;
1770 }
1771#else
1772 FILE* fp = fopen( filepath, mode );
1773#endif
1774 return fp;
1775}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001776
1777void XMLDocument::DeleteNode( XMLNode* node ) {
1778 TIXMLASSERT( node );
1779 TIXMLASSERT(node->_document == this );
1780 if (node->_parent) {
1781 node->_parent->DeleteChild( node );
1782 }
1783 else {
1784 // Isn't in the tree.
1785 // Use the parent delete.
1786 // Also, we need to mark it tracked: we 'know'
1787 // it was never used.
1788 node->_memPool->SetTracked();
1789 // Call the static XMLNode version:
1790 XMLNode::DeleteNode(node);
1791 }
1792}
1793
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001794
Lee Thomason2fa81722012-11-09 12:37:46 -08001795XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001797 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001798 FILE* fp = callfopen( filename, "rb" );
1799 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 }
1803 LoadFile( fp );
1804 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001806}
1807
1808
Lee Thomason2fa81722012-11-09 12:37:46 -08001809XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001811 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001812
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001813 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001814 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001815 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1816 return _errorID;
1817 }
1818
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001820 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001822 if ( filelength == -1L ) {
1823 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1824 return _errorID;
1825 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001827 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001829 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001832
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _charBuffer = new char[size+1];
1834 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 if ( read != size ) {
1836 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001839
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001841
Dmitry-Me97476b72015-01-01 16:15:57 +03001842 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001844}
1845
1846
Lee Thomason2fa81722012-11-09 12:37:46 -08001847XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848{
Dmitry-Me01578db2014-08-19 10:18:48 +04001849 FILE* fp = callfopen( filename, "w" );
1850 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
1854 SaveFile(fp, compact);
1855 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001857}
1858
1859
Lee Thomason2fa81722012-11-09 12:37:46 -08001860XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001861{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 XMLPrinter stream( fp, compact );
1863 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001865}
1866
Lee Thomason1ff38e02012-02-14 18:18:16 -08001867
Lee Thomason2fa81722012-11-09 12:37:46 -08001868XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001869{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001870 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001871
Lee Thomason82d32002014-02-21 22:47:18 -08001872 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 }
1876 if ( len == (size_t)(-1) ) {
1877 len = strlen( p );
1878 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 _charBuffer = new char[ len+1 ];
1880 memcpy( _charBuffer, p, len );
1881 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001882
Dmitry-Me97476b72015-01-01 16:15:57 +03001883 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001884 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001885 // clean up now essentially dangling memory.
1886 // and the parse fail can put objects in the
1887 // pools that are dead and inaccessible.
1888 DeleteChildren();
1889 _elementPool.Clear();
1890 _attributePool.Clear();
1891 _textPool.Clear();
1892 _commentPool.Clear();
1893 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001895}
1896
1897
PKEuS1c5f99e2013-07-06 11:28:39 +02001898void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001899{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 XMLPrinter stdStreamer( stdout );
1901 if ( !streamer ) {
1902 streamer = &stdStreamer;
1903 }
1904 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001905}
1906
1907
Lee Thomason2fa81722012-11-09 12:37:46 -08001908void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001909{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001910 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 _errorID = error;
1912 _errorStr1 = str1;
1913 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001914}
1915
Lee Thomason331596e2014-09-11 14:56:43 -07001916const char* XMLDocument::ErrorName() const
1917{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001918 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001919 return _errorNames[_errorID];
1920}
Lee Thomason5cae8972012-01-24 18:03:07 -08001921
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001922void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001923{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001924 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 static const int LEN = 20;
1926 char buf1[LEN] = { 0 };
1927 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001928
Lee Thomason624d43f2012-10-12 10:58:48 -07001929 if ( _errorStr1 ) {
1930 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 if ( _errorStr2 ) {
1933 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001935
Lee Thomason331596e2014-09-11 14:56:43 -07001936 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1937 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001939}
1940
Dmitry-Me97476b72015-01-01 16:15:57 +03001941void XMLDocument::Parse()
1942{
1943 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1944 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001945 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001946 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001947 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001948 if ( !*p ) {
1949 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1950 return;
1951 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001952 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001953}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001954
PKEuS1bfb9542013-08-04 13:51:17 +02001955XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001956 _elementJustOpened( false ),
1957 _firstElement( true ),
1958 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001959 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 _textDepth( -1 ),
1961 _processEntities( true ),
1962 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001965 _entityFlag[i] = false;
1966 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
1968 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001969 const char entityValue = entities[i].value;
1970 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1971 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001973 _restrictedEntityFlag[(unsigned char)'&'] = true;
1974 _restrictedEntityFlag[(unsigned char)'<'] = true;
1975 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001977}
1978
1979
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001980void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001981{
1982 va_list va;
1983 va_start( va, format );
1984
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 if ( _fp ) {
1986 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 }
1988 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001989#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001990 #if defined(WINCE)
1991 int len = 512;
1992 do {
1993 len = len*2;
1994 char* str = new char[len]();
1995 len = _vsnprintf(str, len, format, va);
1996 delete[] str;
1997 }while (len < 0);
1998 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001999 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002000 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001#else
2002 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002003#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 // Close out and re-start the va-args
2005 va_end( va );
2006 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002007 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002008 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2009#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002010 #if defined(WINCE)
2011 _vsnprintf( p, len+1, format, va );
2012 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002013 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002014 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002015#else
2016 vsnprintf( p, len+1, format, va );
2017#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002019 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002020}
2021
2022
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002023void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 for( int i=0; i<depth; ++i ) {
2026 Print( " " );
2027 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002028}
2029
2030
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002031void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 // Look for runs of bytes between entities to print.
2034 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002035
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002037 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 while ( *q ) {
2039 // Remember, char is sometimes signed. (How many times has that bitten me?)
2040 if ( *q > 0 && *q < ENTITY_RANGE ) {
2041 // Check for entities. If one is found, flush
2042 // the stream up until the entity, write the
2043 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002044 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 while ( p < q ) {
2046 Print( "%c", *p );
2047 ++p;
2048 }
2049 for( int i=0; i<NUM_ENTITIES; ++i ) {
2050 if ( entities[i].value == *q ) {
2051 Print( "&%s;", entities[i].pattern );
2052 break;
2053 }
2054 }
2055 ++p;
2056 }
2057 }
2058 ++q;
2059 }
2060 }
2061 // Flush the remaining string. This will be the entire
2062 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 Print( "%s", p );
2065 }
Lee Thomason857b8682012-01-25 17:50:25 -08002066}
2067
U-Stream\Leeae25a442012-02-17 17:48:16 -08002068
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002069void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002072 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 -07002073 Print( "%s", bom );
2074 }
2075 if ( writeDec ) {
2076 PushDeclaration( "xml version=\"1.0\"" );
2077 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002078}
2079
2080
Uli Kusterer593a33d2014-02-01 12:48:51 +01002081void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002082{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002083 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002085
Uli Kusterer593a33d2014-02-01 12:48:51 +01002086 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002088 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002089 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002092
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 _elementJustOpened = true;
2095 _firstElement = false;
2096 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002097}
2098
2099
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002100void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002101{
Lee Thomason624d43f2012-10-12 10:58:48 -07002102 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 Print( " %s=\"", name );
2104 PrintString( value, false );
2105 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002106}
2107
2108
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002109void XMLPrinter::PushAttribute( const char* name, int v )
2110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 char buf[BUF_SIZE];
2112 XMLUtil::ToStr( v, buf, BUF_SIZE );
2113 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
2116
2117void XMLPrinter::PushAttribute( const char* name, unsigned v )
2118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( v, buf, BUF_SIZE );
2121 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
2124
2125void XMLPrinter::PushAttribute( const char* name, bool v )
2126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 char buf[BUF_SIZE];
2128 XMLUtil::ToStr( v, buf, BUF_SIZE );
2129 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002130}
2131
2132
2133void XMLPrinter::PushAttribute( const char* name, double v )
2134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 char buf[BUF_SIZE];
2136 XMLUtil::ToStr( v, buf, BUF_SIZE );
2137 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002138}
2139
2140
Uli Kustererca412e82014-02-01 13:35:05 +01002141void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002142{
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 --_depth;
2144 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002145
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 Print( "/>" );
2148 }
2149 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002150 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
2154 Print( "</%s>", name );
2155 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002156
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 if ( _textDepth == _depth ) {
2158 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 }
Uli Kustererca412e82014-02-01 13:35:05 +01002160 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 Print( "\n" );
2162 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002164}
2165
2166
Dmitry-Mea092bc12014-12-23 17:57:05 +03002167void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002168{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002169 if ( !_elementJustOpened ) {
2170 return;
2171 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002174}
2175
2176
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002177void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002178{
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002180
Dmitry-Mea092bc12014-12-23 17:57:05 +03002181 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 if ( cdata ) {
2183 Print( "<![CDATA[" );
2184 Print( "%s", text );
2185 Print( "]]>" );
2186 }
2187 else {
2188 PrintString( text, true );
2189 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002190}
2191
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002192void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 char buf[BUF_SIZE];
2195 XMLUtil::ToStr( value, buf, BUF_SIZE );
2196 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002197}
2198
2199
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002200void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 char buf[BUF_SIZE];
2203 XMLUtil::ToStr( value, buf, BUF_SIZE );
2204 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002205}
2206
2207
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002208void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 char buf[BUF_SIZE];
2211 XMLUtil::ToStr( value, buf, BUF_SIZE );
2212 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002213}
2214
2215
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002216void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 char buf[BUF_SIZE];
2219 XMLUtil::ToStr( value, buf, BUF_SIZE );
2220 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002221}
2222
2223
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002224void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 char buf[BUF_SIZE];
2227 XMLUtil::ToStr( value, buf, BUF_SIZE );
2228 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002229}
2230
Lee Thomason5cae8972012-01-24 18:03:07 -08002231
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002232void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002233{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002234 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002241}
Lee Thomason751da522012-02-10 08:50:51 -08002242
2243
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002244void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002245{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002246 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002253}
2254
2255
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002256void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002257{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002258 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002265}
2266
2267
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002268bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002269{
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 if ( doc.HasBOM() ) {
2272 PushHeader( true, false );
2273 }
2274 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002275}
2276
2277
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002278bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002279{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002280 const XMLElement* parentElem = element.Parent()->ToElement();
2281 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2282 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 while ( attribute ) {
2284 PushAttribute( attribute->Name(), attribute->Value() );
2285 attribute = attribute->Next();
2286 }
2287 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002288}
2289
2290
Uli Kustererca412e82014-02-01 13:35:05 +01002291bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002292{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002293 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002295}
2296
2297
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002298bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 PushText( text.Value(), text.CData() );
2301 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 XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 PushComment( comment.Value() );
2308 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002309}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002310
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002311bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 PushDeclaration( declaration.Value() );
2314 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002315}
2316
2317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 PushUnknown( unknown.Value() );
2321 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002323
Lee Thomason685b8952012-11-12 13:00:06 -08002324} // namespace tinyxml2
2325