blob: 377ad23496387434b845643b8893c1fd7ae20c69 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300231 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
232 if ( adjusted == 0 ) {
233 *q = *p;
234 ++p;
235 ++q;
236 }
237 else {
238 TIXMLASSERT( 0 <= len && len <= buflen );
239 TIXMLASSERT( q + len <= adjusted );
240 p = adjusted;
241 memcpy( q, buf, len );
242 q += len;
243 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700244 }
245 else {
246 int i=0;
247 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400248 const Entity& entity = entities[i];
249 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
250 && *( p + entity.length + 1 ) == ';' ) {
251 // Found an entity - convert.
252 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700253 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400254 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 break;
256 }
257 }
258 if ( i == NUM_ENTITIES ) {
259 // fixme: treat as error?
260 ++p;
261 ++q;
262 }
263 }
264 }
265 else {
266 *q = *p;
267 ++p;
268 ++q;
269 }
270 }
271 *q = 0;
272 }
273 // The loop below has plenty going on, and this
274 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700276 CollapseWhitespace();
277 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700279 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300280 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700281 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800282}
283
Lee Thomason2c85a712012-01-31 08:24:24 -0800284
Lee Thomasone4422302012-01-20 17:59:50 -0800285
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800286
Lee Thomason56bdd022012-02-09 18:16:58 -0800287// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800288
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800289const char* XMLUtil::ReadBOM( const char* p, bool* bom )
290{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300291 TIXMLASSERT( p );
292 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 *bom = false;
294 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
295 // Check for BOM:
296 if ( *(pu+0) == TIXML_UTF_LEAD_0
297 && *(pu+1) == TIXML_UTF_LEAD_1
298 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
299 *bom = true;
300 p += 3;
301 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300302 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304}
305
306
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800307void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 const unsigned long BYTE_MASK = 0xBF;
310 const unsigned long BYTE_MARK = 0x80;
311 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800312
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 if (input < 0x80) {
314 *length = 1;
315 }
316 else if ( input < 0x800 ) {
317 *length = 2;
318 }
319 else if ( input < 0x10000 ) {
320 *length = 3;
321 }
322 else if ( input < 0x200000 ) {
323 *length = 4;
324 }
325 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300326 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 return;
328 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800329
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800331
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Scary scary fall throughs.
333 switch (*length) {
334 case 4:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 3:
339 --output;
340 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
341 input >>= 6;
342 case 2:
343 --output;
344 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
345 input >>= 6;
346 case 1:
347 --output;
348 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100349 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300350 default:
351 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353}
354
355
356const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 // Presume an entity, and pull it out.
359 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800360
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 if ( *(p+1) == '#' && *(p+2) ) {
362 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300363 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 ptrdiff_t delta = 0;
365 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 if ( *(p+2) == 'x' ) {
369 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300370 const char* q = p+3;
371 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 return 0;
373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374
Lee Thomason7e67bc82015-01-12 14:05:12 -0800375 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800376
Dmitry-Me9f56e122015-01-12 10:07:54 +0300377 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 return 0;
379 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800380 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 delta = q-p;
383 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700386 unsigned int digit = 0;
387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300389 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 }
391 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300392 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 }
394 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300395 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 }
397 else {
398 return 0;
399 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300400 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300401 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
402 const unsigned int digitScaled = mult * digit;
403 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
404 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300405 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 mult *= 16;
407 --q;
408 }
409 }
410 else {
411 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300412 const char* q = p+2;
413 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 return 0;
415 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416
Lee Thomason7e67bc82015-01-12 14:05:12 -0800417 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800418
Dmitry-Me9f56e122015-01-12 10:07:54 +0300419 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700420 return 0;
421 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800422 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800423
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 delta = q-p;
425 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 while ( *q != '#' ) {
428 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300429 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300430 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300431 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
432 const unsigned int digitScaled = mult * digit;
433 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
434 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 }
436 else {
437 return 0;
438 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300439 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 mult *= 10;
441 --q;
442 }
443 }
444 // convert the UCS to UTF-8
445 ConvertUTF32ToUTF8( ucs, value, length );
446 return p + delta + 1;
447 }
448 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800450
451
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700452void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700467}
468
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800469/*
470 ToStr() of a number is a very tricky topic.
471 https://github.com/leethomason/tinyxml2/issues/106
472*/
Lee Thomason21be8822012-07-15 17:27:22 -0700473void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
474{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800475 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700476}
477
478
479void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
480{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800481 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484
485bool XMLUtil::ToInt( const char* str, int* value )
486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
488 return true;
489 }
490 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700491}
492
493bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToBool( const char* str, bool* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 int ival = 0;
504 if ( ToInt( str, &ival )) {
505 *value = (ival==0) ? false : true;
506 return true;
507 }
508 if ( StringEqual( str, "true" ) ) {
509 *value = true;
510 return true;
511 }
512 else if ( StringEqual( str, "false" ) ) {
513 *value = false;
514 return true;
515 }
516 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700517}
518
519
520bool XMLUtil::ToFloat( const char* str, float* value )
521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
523 return true;
524 }
525 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700526}
527
528bool XMLUtil::ToDouble( const char* str, double* value )
529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
531 return true;
532 }
533 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700537char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800538{
Dmitry-Me02384662015-03-03 16:02:13 +0300539 TIXMLASSERT( node );
540 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400541 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300543 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300544 *node = 0;
545 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 return p;
547 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800548
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 static const char* xmlHeader = { "<?" };
552 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300554 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800556
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 static const int xmlHeaderLen = 2;
558 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300560 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
564 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400565 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300567 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700568 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
569 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 p += xmlHeaderLen;
571 }
572 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300573 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700574 returnNode = new (_commentPool.Alloc()) XMLComment( this );
575 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 p += commentHeaderLen;
577 }
578 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300579 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 p += cdataHeaderLen;
584 text->SetCData( true );
585 }
586 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300587 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700588 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
589 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 p += dtdHeaderLen;
591 }
592 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300593 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 returnNode = new (_elementPool.Alloc()) XMLElement( this );
595 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 p += elementHeaderLen;
597 }
598 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300599 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700600 returnNode = new (_textPool.Alloc()) XMLText( this );
601 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 p = start; // Back it up, all the text counts.
603 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604
Dmitry-Me02384662015-03-03 16:02:13 +0300605 TIXMLASSERT( returnNode );
606 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 *node = returnNode;
608 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800609}
610
611
Lee Thomason751da522012-02-10 08:50:51 -0800612bool XMLDocument::Accept( XMLVisitor* visitor ) const
613{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300614 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 if ( visitor->VisitEnter( *this ) ) {
616 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
617 if ( !node->Accept( visitor ) ) {
618 break;
619 }
620 }
621 }
622 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800623}
Lee Thomason56bdd022012-02-09 18:16:58 -0800624
625
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800626// --------- XMLNode ----------- //
627
628XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 _document( doc ),
630 _parent( 0 ),
631 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200632 _prev( 0 ), _next( 0 ),
633 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635}
636
637
638XMLNode::~XMLNode()
639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 if ( _parent ) {
642 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800644}
645
Michael Daumling21626882013-10-22 17:03:37 +0200646const char* XMLNode::Value() const
647{
648 return _value.GetStr();
649}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800650
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800651void XMLNode::SetValue( const char* str, bool staticMem )
652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800659}
660
661
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800662void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800663{
Lee Thomason624d43f2012-10-12 10:58:48 -0700664 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300665 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300666 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700669
Dmitry-Mee3225b12014-09-03 11:03:11 +0400670 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800673}
674
675
676void XMLNode::Unlink( XMLNode* child )
677{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300678 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300679 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300680 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 if ( child == _firstChild ) {
682 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 if ( child == _lastChild ) {
685 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
Lee Thomasond923c672012-01-23 08:44:25 -0800687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( child->_prev ) {
689 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 if ( child->_next ) {
692 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700694 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695}
696
697
U-Stream\Leeae25a442012-02-17 17:48:16 -0800698void XMLNode::DeleteChild( XMLNode* node )
699{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300700 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300701 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400703 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800704}
705
706
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
708{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300709 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300710 if ( addThis->_document != _document ) {
711 TIXMLASSERT( false );
712 return 0;
713 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800714 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700715
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 if ( _lastChild ) {
717 TIXMLASSERT( _firstChild );
718 TIXMLASSERT( _lastChild->_next == 0 );
719 _lastChild->_next = addThis;
720 addThis->_prev = _lastChild;
721 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 TIXMLASSERT( _firstChild == 0 );
727 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
730 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800734}
735
736
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
738{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300739 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 if ( addThis->_document != _document ) {
741 TIXMLASSERT( false );
742 return 0;
743 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800744 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700745
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 if ( _firstChild ) {
747 TIXMLASSERT( _lastChild );
748 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800749
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 _firstChild->_prev = addThis;
751 addThis->_next = _firstChild;
752 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
756 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 TIXMLASSERT( _lastChild == 0 );
758 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800759
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_prev = 0;
761 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400764 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800765}
766
767
768XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
769{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300770 TIXMLASSERT( addThis );
771 if ( addThis->_document != _document ) {
772 TIXMLASSERT( false );
773 return 0;
774 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700775
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700777
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300779 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 return 0;
781 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800782
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 // The last node or the only node.
785 return InsertEndChild( addThis );
786 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800787 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 addThis->_prev = afterThis;
789 addThis->_next = afterThis->_next;
790 afterThis->_next->_prev = addThis;
791 afterThis->_next = addThis;
792 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800794}
795
796
797
798
Lee Thomason56bdd022012-02-09 18:16:58 -0800799const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800800{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300801 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
802 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 if ( element ) {
804 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
805 return element;
806 }
807 }
808 }
809 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800810}
811
812
Lee Thomason56bdd022012-02-09 18:16:58 -0800813const XMLElement* XMLNode::LastChildElement( const char* value ) const
814{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300815 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
816 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 if ( element ) {
818 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
819 return element;
820 }
821 }
822 }
823 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800824}
825
826
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800827const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
828{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300829 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400830 const XMLElement* element = node->ToElement();
831 if ( element
832 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
833 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
835 }
836 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800837}
838
839
840const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
841{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300842 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400843 const XMLElement* element = node->ToElement();
844 if ( element
845 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
846 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 }
848 }
849 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800850}
851
852
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800853char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800854{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 // This is a recursive method, but thinking about it "at the current level"
856 // it is a pretty simple flat list:
857 // <foo/>
858 // <!-- comment -->
859 //
860 // With a special case:
861 // <foo>
862 // </foo>
863 // <!-- comment -->
864 //
865 // Where the closing element (/foo) *must* be the next thing after the opening
866 // element, and the names must match. BUT the tricky bit is that the closing
867 // element will be read by the child.
868 //
869 // 'endTag' is the end tag for this node, it is returned by a call to a child.
870 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800871
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 while( p && *p ) {
873 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800874
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300876 if ( node == 0 ) {
877 break;
878 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800879
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 StrPair endTag;
881 p = node->ParseDeep( p, &endTag );
882 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400883 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 if ( !_document->Error() ) {
885 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 break;
888 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530889
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530890 XMLElement* ele = node->ToDeclaration();
891 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530892 // A declaration can only be the first child of a document.
893 // Set error, if document already has children.
894 if ( !_document->NoChildren() ) {
895 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
896 DeleteNode( decl );
897 break;
898 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530899 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530900
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400901 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500903 // We read the end tag. Return it to the parent.
904 if ( ele->ClosingType() == XMLElement::CLOSING ) {
905 if ( parentEnd ) {
906 ele->_value.TransferTo( parentEnd );
907 }
908 node->_memPool->SetTracked(); // created and then immediately deleted.
909 DeleteNode( node );
910 return p;
911 }
912
913 // Handle an end tag returned to this level.
914 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400915 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300916 if ( endTag.Empty() ) {
917 if ( ele->ClosingType() == XMLElement::OPEN ) {
918 mismatch = true;
919 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300921 else {
922 if ( ele->ClosingType() != XMLElement::OPEN ) {
923 mismatch = true;
924 }
925 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400926 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400929 if ( mismatch ) {
930 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500931 DeleteNode( node );
932 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400933 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 }
JayXondbfdd8f2014-12-12 20:07:14 -0500935 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 }
937 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800938}
939
Dmitry-Mee3225b12014-09-03 11:03:11 +0400940void XMLNode::DeleteNode( XMLNode* node )
941{
942 if ( node == 0 ) {
943 return;
944 }
945 MemPool* pool = node->_memPool;
946 node->~XMLNode();
947 pool->Free( node );
948}
949
Lee Thomason3cebdc42015-01-05 17:16:28 -0800950void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300951{
952 TIXMLASSERT( insertThis );
953 TIXMLASSERT( insertThis->_document == _document );
954
955 if ( insertThis->_parent )
956 insertThis->_parent->Unlink( insertThis );
957 else
958 insertThis->_memPool->SetTracked();
959}
960
Lee Thomason5492a1c2012-01-23 15:32:10 -0800961// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800962char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 const char* start = p;
965 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700966 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 return p;
971 }
972 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700973 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
974 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 flags |= StrPair::COLLAPSE_WHITESPACE;
976 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700977
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 if ( p && *p ) {
980 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300981 }
982 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300983 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 }
986 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800987}
988
989
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800990XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
996 text->SetCData( this->CData() );
997 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998}
999
1000
1001bool XMLText::ShallowEqual( const XMLNode* compare ) const
1002{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001003 const XMLText* text = compare->ToText();
1004 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
Lee Thomason56bdd022012-02-09 18:16:58 -08001008bool XMLText::Accept( XMLVisitor* visitor ) const
1009{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001010 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001012}
1013
1014
Lee Thomason3f57d272012-01-11 15:30:03 -08001015// --------- XMLComment ---------- //
1016
Lee Thomasone4422302012-01-20 17:59:50 -08001017XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001018{
1019}
1020
1021
Lee Thomasonce0763e2012-01-11 15:43:54 -08001022XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001023{
Lee Thomason3f57d272012-01-11 15:30:03 -08001024}
1025
1026
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001027char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 // Comment parses as text.
1030 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001036}
1037
1038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001039XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1045 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046}
1047
1048
1049bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1050{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001051 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001052 const XMLComment* comment = compare->ToComment();
1053 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054}
1055
1056
Lee Thomason751da522012-02-10 08:50:51 -08001057bool XMLComment::Accept( XMLVisitor* visitor ) const
1058{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001059 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001061}
Lee Thomason56bdd022012-02-09 18:16:58 -08001062
1063
Lee Thomason50f97b22012-02-11 16:33:40 -08001064// --------- XMLDeclaration ---------- //
1065
1066XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1067{
1068}
1069
1070
1071XMLDeclaration::~XMLDeclaration()
1072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001074}
1075
1076
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001077char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Declaration parses as text.
1080 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001086}
1087
1088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001089XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001092 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 }
1094 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1095 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001101 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001102 const XMLDeclaration* declaration = compare->ToDeclaration();
1103 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001104}
1105
1106
1107
Lee Thomason50f97b22012-02-11 16:33:40 -08001108bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1109{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001110 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001112}
1113
1114// --------- XMLUnknown ---------- //
1115
1116XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1117{
1118}
1119
1120
1121XMLUnknown::~XMLUnknown()
1122{
1123}
1124
1125
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001126char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 // Unknown parses as text.
1129 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001130
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001133 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 }
1135 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001136}
1137
1138
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001139XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001142 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 }
1144 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1145 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001146}
1147
1148
1149bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1150{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001151 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001152 const XMLUnknown* unknown = compare->ToUnknown();
1153 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001154}
1155
1156
Lee Thomason50f97b22012-02-11 16:33:40 -08001157bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1158{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001159 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001161}
1162
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001163// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001164
1165const char* XMLAttribute::Name() const
1166{
1167 return _name.GetStr();
1168}
1169
1170const char* XMLAttribute::Value() const
1171{
1172 return _value.GetStr();
1173}
1174
Lee Thomason6f381b72012-03-02 12:59:39 -08001175char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001178 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( !p || !*p ) {
1180 return 0;
1181 }
Lee Thomason22aead12012-01-23 13:29:35 -08001182
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 // Skip white space before =
1184 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001185 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 return 0;
1187 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001188
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 ++p; // move up to opening quote
1190 p = XMLUtil::SkipWhiteSpace( p );
1191 if ( *p != '\"' && *p != '\'' ) {
1192 return 0;
1193 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001194
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char endTag[2] = { *p, 0 };
1196 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001197
Lee Thomason624d43f2012-10-12 10:58:48 -07001198 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001200}
1201
1202
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001203void XMLAttribute::SetName( const char* n )
1204{
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001206}
1207
1208
Lee Thomason2fa81722012-11-09 12:37:46 -08001209XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 if ( XMLUtil::ToInt( Value(), value )) {
1212 return XML_NO_ERROR;
1213 }
1214 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215}
1216
1217
Lee Thomason2fa81722012-11-09 12:37:46 -08001218XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 if ( XMLUtil::ToUnsigned( Value(), value )) {
1221 return XML_NO_ERROR;
1222 }
1223 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001224}
1225
1226
Lee Thomason2fa81722012-11-09 12:37:46 -08001227XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( XMLUtil::ToBool( Value(), value )) {
1230 return XML_NO_ERROR;
1231 }
1232 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001233}
1234
1235
Lee Thomason2fa81722012-11-09 12:37:46 -08001236XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( XMLUtil::ToFloat( Value(), value )) {
1239 return XML_NO_ERROR;
1240 }
1241 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001242}
1243
1244
Lee Thomason2fa81722012-11-09 12:37:46 -08001245XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( XMLUtil::ToDouble( Value(), value )) {
1248 return XML_NO_ERROR;
1249 }
1250 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001251}
1252
1253
1254void XMLAttribute::SetAttribute( const char* v )
1255{
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001257}
1258
1259
Lee Thomason1ff38e02012-02-14 18:18:16 -08001260void XMLAttribute::SetAttribute( int v )
1261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 char buf[BUF_SIZE];
1263 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001265}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001266
1267
1268void XMLAttribute::SetAttribute( unsigned v )
1269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 char buf[BUF_SIZE];
1271 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001272 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001273}
1274
1275
1276void XMLAttribute::SetAttribute( bool v )
1277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 char buf[BUF_SIZE];
1279 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001280 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001281}
1282
1283void XMLAttribute::SetAttribute( double v )
1284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 char buf[BUF_SIZE];
1286 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001287 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001288}
1289
1290void XMLAttribute::SetAttribute( float v )
1291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001294 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001295}
1296
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001297
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001298// --------- XMLElement ---------- //
1299XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001300 _closingType( 0 ),
1301 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001302{
1303}
1304
1305
1306XMLElement::~XMLElement()
1307{
Lee Thomason624d43f2012-10-12 10:58:48 -07001308 while( _rootAttribute ) {
1309 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001310 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001313}
1314
1315
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001316const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1317{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001318 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1320 return a;
1321 }
1322 }
1323 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001324}
1325
1326
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001327const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 const XMLAttribute* a = FindAttribute( name );
1330 if ( !a ) {
1331 return 0;
1332 }
1333 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1334 return a->Value();
1335 }
1336 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001337}
1338
1339
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001340const char* XMLElement::GetText() const
1341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001343 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 }
1345 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001346}
1347
1348
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001349void XMLElement::SetText( const char* inText )
1350{
Uli Kusterer869bb592014-01-21 01:36:16 +01001351 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001352 FirstChild()->SetValue( inText );
1353 else {
1354 XMLText* theText = GetDocument()->NewText( inText );
1355 InsertFirstChild( theText );
1356 }
1357}
1358
Lee Thomason5bb2d802014-01-24 10:42:57 -08001359
1360void XMLElement::SetText( int v )
1361{
1362 char buf[BUF_SIZE];
1363 XMLUtil::ToStr( v, buf, BUF_SIZE );
1364 SetText( buf );
1365}
1366
1367
1368void XMLElement::SetText( unsigned v )
1369{
1370 char buf[BUF_SIZE];
1371 XMLUtil::ToStr( v, buf, BUF_SIZE );
1372 SetText( buf );
1373}
1374
1375
1376void XMLElement::SetText( bool v )
1377{
1378 char buf[BUF_SIZE];
1379 XMLUtil::ToStr( v, buf, BUF_SIZE );
1380 SetText( buf );
1381}
1382
1383
1384void XMLElement::SetText( float v )
1385{
1386 char buf[BUF_SIZE];
1387 XMLUtil::ToStr( v, buf, BUF_SIZE );
1388 SetText( buf );
1389}
1390
1391
1392void XMLElement::SetText( double v )
1393{
1394 char buf[BUF_SIZE];
1395 XMLUtil::ToStr( v, buf, BUF_SIZE );
1396 SetText( buf );
1397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001416 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 return XML_SUCCESS;
1419 }
1420 return XML_CAN_NOT_CONVERT_TEXT;
1421 }
1422 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
MortenMacFly4ee49f12013-01-14 20:03:14 +01001426XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001429 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001430 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 return XML_SUCCESS;
1432 }
1433 return XML_CAN_NOT_CONVERT_TEXT;
1434 }
1435 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001436}
1437
1438
MortenMacFly4ee49f12013-01-14 20:03:14 +01001439XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001442 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001443 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 return XML_SUCCESS;
1445 }
1446 return XML_CAN_NOT_CONVERT_TEXT;
1447 }
1448 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001449}
1450
1451
MortenMacFly4ee49f12013-01-14 20:03:14 +01001452XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001455 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001456 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 return XML_SUCCESS;
1458 }
1459 return XML_CAN_NOT_CONVERT_TEXT;
1460 }
1461 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001462}
1463
1464
1465
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001466XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 XMLAttribute* last = 0;
1469 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1474 break;
1475 }
1476 }
1477 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001478 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1480 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 }
1484 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 }
1487 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001488 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 }
1490 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001491}
1492
1493
U-Stream\Leeae25a442012-02-17 17:48:16 -08001494void XMLElement::DeleteAttribute( const char* name )
1495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1499 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
1502 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001505 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 break;
1507 }
1508 prev = a;
1509 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001510}
1511
1512
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001513char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001514{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 const char* start = p;
1516 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 // Read the attributes.
1519 while( p ) {
1520 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001521 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 return 0;
1524 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001527 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001528 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001529 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1530 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001531 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001532
Lee Thomason624d43f2012-10-12 10:58:48 -07001533 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001535 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 return 0;
1538 }
1539 // There is a minor bug here: if the attribute in the source xml
1540 // document is duplicated, it will not be detected and the
1541 // attribute will be doubly added. However, tracking the 'prevAttribute'
1542 // avoids re-scanning the attribute list. Preferring performance for
1543 // now, may reconsider in the future.
1544 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 }
1547 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 }
1550 prevAttribute = attrib;
1551 }
1552 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 else if ( *p == '>' ) {
1554 ++p;
1555 break;
1556 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001557 // end of the tag
1558 else if ( *p == '/' && *(p+1) == '>' ) {
1559 _closingType = CLOSED;
1560 return p+2; // done; sealed element.
1561 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001563 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 return 0;
1565 }
1566 }
1567 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001568}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001569
Dmitry-Mee3225b12014-09-03 11:03:11 +04001570void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1571{
1572 if ( attribute == 0 ) {
1573 return;
1574 }
1575 MemPool* pool = attribute->_memPool;
1576 attribute->~XMLAttribute();
1577 pool->Free( attribute );
1578}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001579
Lee Thomason67d61312012-01-24 16:01:51 -08001580//
1581// <ele></ele>
1582// <ele>foo<b>bar</b></ele>
1583//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001584char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001585{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 // Read the element name.
1587 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001588
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 // The closing element is the </element> form. It is
1590 // parsed just like a regular element then deleted from
1591 // the DOM.
1592 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001593 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 ++p;
1595 }
Lee Thomason67d61312012-01-24 16:01:51 -08001596
Lee Thomason624d43f2012-10-12 10:58:48 -07001597 p = _value.ParseName( p );
1598 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 return 0;
1600 }
Lee Thomason67d61312012-01-24 16:01:51 -08001601
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 return p;
1605 }
Lee Thomason67d61312012-01-24 16:01:51 -08001606
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 p = XMLNode::ParseDeep( p, strPair );
1608 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001609}
1610
1611
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001612
1613XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 }
1618 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1619 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1620 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1621 }
1622 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001623}
1624
1625
1626bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1627{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001628 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 const XMLElement* other = compare->ToElement();
1630 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001631
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 const XMLAttribute* a=FirstAttribute();
1633 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001634
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 while ( a && b ) {
1636 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1637 return false;
1638 }
1639 a = a->Next();
1640 b = b->Next();
1641 }
1642 if ( a || b ) {
1643 // different count
1644 return false;
1645 }
1646 return true;
1647 }
1648 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001649}
1650
1651
Lee Thomason751da522012-02-10 08:50:51 -08001652bool XMLElement::Accept( XMLVisitor* visitor ) const
1653{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001654 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1657 if ( !node->Accept( visitor ) ) {
1658 break;
1659 }
1660 }
1661 }
1662 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001663}
Lee Thomason56bdd022012-02-09 18:16:58 -08001664
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001665
Lee Thomason3f57d272012-01-11 15:30:03 -08001666// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001667
1668// Warning: List must match 'enum XMLError'
1669const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1670 "XML_SUCCESS",
1671 "XML_NO_ATTRIBUTE",
1672 "XML_WRONG_ATTRIBUTE_TYPE",
1673 "XML_ERROR_FILE_NOT_FOUND",
1674 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1675 "XML_ERROR_FILE_READ_ERROR",
1676 "XML_ERROR_ELEMENT_MISMATCH",
1677 "XML_ERROR_PARSING_ELEMENT",
1678 "XML_ERROR_PARSING_ATTRIBUTE",
1679 "XML_ERROR_IDENTIFYING_TAG",
1680 "XML_ERROR_PARSING_TEXT",
1681 "XML_ERROR_PARSING_CDATA",
1682 "XML_ERROR_PARSING_COMMENT",
1683 "XML_ERROR_PARSING_DECLARATION",
1684 "XML_ERROR_PARSING_UNKNOWN",
1685 "XML_ERROR_EMPTY_DOCUMENT",
1686 "XML_ERROR_MISMATCHED_ELEMENT",
1687 "XML_ERROR_PARSING",
1688 "XML_CAN_NOT_CONVERT_TEXT",
1689 "XML_NO_TEXT_NODE"
1690};
1691
1692
Lee Thomason624d43f2012-10-12 10:58:48 -07001693XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 _writeBOM( false ),
1696 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001697 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 _whitespace( whitespace ),
1699 _errorStr1( 0 ),
1700 _errorStr2( 0 ),
1701 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001702{
Lee Thomason624d43f2012-10-12 10:58:48 -07001703 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001704}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001705
1706
Lee Thomason3f57d272012-01-11 15:30:03 -08001707XMLDocument::~XMLDocument()
1708{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001709 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001710}
1711
1712
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001713void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001714{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001715 DeleteChildren();
1716
Dmitry-Meab37df82014-11-28 12:08:36 +03001717#ifdef DEBUG
1718 const bool hadError = Error();
1719#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 _errorID = XML_NO_ERROR;
1721 _errorStr1 = 0;
1722 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001723
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 delete [] _charBuffer;
1725 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001726
1727#if 0
1728 _textPool.Trace( "text" );
1729 _elementPool.Trace( "element" );
1730 _commentPool.Trace( "comment" );
1731 _attributePool.Trace( "attribute" );
1732#endif
1733
1734#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001735 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001736 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1737 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1738 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1739 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1740 }
1741#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001742}
1743
Lee Thomason3f57d272012-01-11 15:30:03 -08001744
Lee Thomason2c85a712012-01-31 08:24:24 -08001745XMLElement* XMLDocument::NewElement( const char* name )
1746{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001747 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1749 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 ele->SetName( name );
1751 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001752}
1753
1754
Lee Thomason1ff38e02012-02-14 18:18:16 -08001755XMLComment* XMLDocument::NewComment( const char* str )
1756{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001757 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1759 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 comment->SetValue( str );
1761 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001762}
1763
1764
1765XMLText* XMLDocument::NewText( const char* str )
1766{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001767 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1769 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 text->SetValue( str );
1771 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001772}
1773
1774
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001775XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1776{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001777 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1779 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1781 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001782}
1783
1784
1785XMLUnknown* XMLDocument::NewUnknown( const char* str )
1786{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001787 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1789 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 unk->SetValue( str );
1791 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001792}
1793
Dmitry-Me01578db2014-08-19 10:18:48 +04001794static FILE* callfopen( const char* filepath, const char* mode )
1795{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001796 TIXMLASSERT( filepath );
1797 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001798#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1799 FILE* fp = 0;
1800 errno_t err = fopen_s( &fp, filepath, mode );
1801 if ( err ) {
1802 return 0;
1803 }
1804#else
1805 FILE* fp = fopen( filepath, mode );
1806#endif
1807 return fp;
1808}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001809
1810void XMLDocument::DeleteNode( XMLNode* node ) {
1811 TIXMLASSERT( node );
1812 TIXMLASSERT(node->_document == this );
1813 if (node->_parent) {
1814 node->_parent->DeleteChild( node );
1815 }
1816 else {
1817 // Isn't in the tree.
1818 // Use the parent delete.
1819 // Also, we need to mark it tracked: we 'know'
1820 // it was never used.
1821 node->_memPool->SetTracked();
1822 // Call the static XMLNode version:
1823 XMLNode::DeleteNode(node);
1824 }
1825}
1826
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001827
Lee Thomason2fa81722012-11-09 12:37:46 -08001828XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001830 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001831 FILE* fp = callfopen( filename, "rb" );
1832 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 }
1836 LoadFile( fp );
1837 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001839}
1840
1841
Lee Thomason2fa81722012-11-09 12:37:46 -08001842XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001843{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001844 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001845
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001846 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001847 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001848 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1849 return _errorID;
1850 }
1851
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001853 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001855 if ( filelength == -1L ) {
1856 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1857 return _errorID;
1858 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001859
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001860 if ( filelength >= (size_t)-1 ) {
1861 // Cannot handle files which won't fit in buffer together with null terminator
1862 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1863 return _errorID;
1864 }
1865
Dmitry-Me72801b82015-05-07 09:41:39 +03001866 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001867 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001870
Dmitry-Me72801b82015-05-07 09:41:39 +03001871 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _charBuffer = new char[size+1];
1873 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 if ( read != size ) {
1875 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001878
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001880
Dmitry-Me97476b72015-01-01 16:15:57 +03001881 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001883}
1884
1885
Lee Thomason2fa81722012-11-09 12:37:46 -08001886XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001887{
Dmitry-Me01578db2014-08-19 10:18:48 +04001888 FILE* fp = callfopen( filename, "w" );
1889 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
1893 SaveFile(fp, compact);
1894 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001896}
1897
1898
Lee Thomason2fa81722012-11-09 12:37:46 -08001899XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001900{
Ant Mitchell189198f2015-03-24 16:20:36 +00001901 // Clear any error from the last save, otherwise it will get reported
1902 // for *this* call.
1903 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 XMLPrinter stream( fp, compact );
1905 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001907}
1908
Lee Thomason1ff38e02012-02-14 18:18:16 -08001909
Lee Thomason2fa81722012-11-09 12:37:46 -08001910XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001911{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001912 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001913
Lee Thomason82d32002014-02-21 22:47:18 -08001914 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 }
1918 if ( len == (size_t)(-1) ) {
1919 len = strlen( p );
1920 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 _charBuffer = new char[ len+1 ];
1922 memcpy( _charBuffer, p, len );
1923 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001924
Dmitry-Me97476b72015-01-01 16:15:57 +03001925 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001926 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001927 // clean up now essentially dangling memory.
1928 // and the parse fail can put objects in the
1929 // pools that are dead and inaccessible.
1930 DeleteChildren();
1931 _elementPool.Clear();
1932 _attributePool.Clear();
1933 _textPool.Clear();
1934 _commentPool.Clear();
1935 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001937}
1938
1939
PKEuS1c5f99e2013-07-06 11:28:39 +02001940void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001942 XMLPrinter stdStreamer( stdout );
1943 if ( !streamer ) {
1944 streamer = &stdStreamer;
1945 }
1946 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001947}
1948
1949
Lee Thomason2fa81722012-11-09 12:37:46 -08001950void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001951{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001952 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 _errorID = error;
1954 _errorStr1 = str1;
1955 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001956}
1957
Lee Thomason331596e2014-09-11 14:56:43 -07001958const char* XMLDocument::ErrorName() const
1959{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001960 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001961 return _errorNames[_errorID];
1962}
Lee Thomason5cae8972012-01-24 18:03:07 -08001963
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001964void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001965{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001966 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 static const int LEN = 20;
1968 char buf1[LEN] = { 0 };
1969 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001970
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 if ( _errorStr1 ) {
1972 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 if ( _errorStr2 ) {
1975 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977
Dmitry-Me2ad43202015-04-16 12:18:58 +03001978 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
1979 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
1980 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07001981 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001982 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001984}
1985
Dmitry-Me97476b72015-01-01 16:15:57 +03001986void XMLDocument::Parse()
1987{
1988 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1989 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001990 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001991 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001992 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001993 if ( !*p ) {
1994 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1995 return;
1996 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001997 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001998}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999
PKEuS1bfb9542013-08-04 13:51:17 +02002000XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _elementJustOpened( false ),
2002 _firstElement( true ),
2003 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002004 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002005 _textDepth( -1 ),
2006 _processEntities( true ),
2007 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 _entityFlag[i] = false;
2011 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 }
2013 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002014 const char entityValue = entities[i].value;
2015 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2016 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002018 _restrictedEntityFlag[(unsigned char)'&'] = true;
2019 _restrictedEntityFlag[(unsigned char)'<'] = true;
2020 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002022}
2023
2024
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002025void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002026{
2027 va_list va;
2028 va_start( va, format );
2029
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 if ( _fp ) {
2031 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 }
2033 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002034#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002035 #if defined(WINCE)
2036 int len = 512;
2037 do {
2038 len = len*2;
2039 char* str = new char[len]();
2040 len = _vsnprintf(str, len, format, va);
2041 delete[] str;
2042 }while (len < 0);
2043 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002044 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002045 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046#else
2047 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002048#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 // Close out and re-start the va-args
2050 va_end( va );
2051 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002052 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002053 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2054#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002055 #if defined(WINCE)
2056 _vsnprintf( p, len+1, format, va );
2057 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002058 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002059 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002060#else
2061 vsnprintf( p, len+1, format, va );
2062#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002064 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002065}
2066
2067
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002068void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 for( int i=0; i<depth; ++i ) {
2071 Print( " " );
2072 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002073}
2074
2075
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002076void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 // Look for runs of bytes between entities to print.
2079 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002080
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002082 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002084 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 // Remember, char is sometimes signed. (How many times has that bitten me?)
2086 if ( *q > 0 && *q < ENTITY_RANGE ) {
2087 // Check for entities. If one is found, flush
2088 // the stream up until the entity, write the
2089 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002090 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002092 const size_t delta = q - p;
2093 // %.*s accepts type int as "precision"
2094 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2095 Print( "%.*s", toPrint, p );
2096 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 }
2098 for( int i=0; i<NUM_ENTITIES; ++i ) {
2099 if ( entities[i].value == *q ) {
2100 Print( "&%s;", entities[i].pattern );
2101 break;
2102 }
2103 }
2104 ++p;
2105 }
2106 }
2107 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002108 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 }
2110 }
2111 // Flush the remaining string. This will be the entire
2112 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002113 TIXMLASSERT( p <= q );
2114 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 Print( "%s", p );
2116 }
Lee Thomason857b8682012-01-25 17:50:25 -08002117}
2118
U-Stream\Leeae25a442012-02-17 17:48:16 -08002119
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002120void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002123 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 -07002124 Print( "%s", bom );
2125 }
2126 if ( writeDec ) {
2127 PushDeclaration( "xml version=\"1.0\"" );
2128 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002129}
2130
2131
Uli Kusterer593a33d2014-02-01 12:48:51 +01002132void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002133{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002134 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002136
Uli Kusterer593a33d2014-02-01 12:48:51 +01002137 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002139 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002140 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002143
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _elementJustOpened = true;
2146 _firstElement = false;
2147 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002148}
2149
2150
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002151void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002152{
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 Print( " %s=\"", name );
2155 PrintString( value, false );
2156 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002157}
2158
2159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002160void XMLPrinter::PushAttribute( const char* name, int v )
2161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 char buf[BUF_SIZE];
2163 XMLUtil::ToStr( v, buf, BUF_SIZE );
2164 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002165}
2166
2167
2168void XMLPrinter::PushAttribute( const char* name, unsigned v )
2169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 char buf[BUF_SIZE];
2171 XMLUtil::ToStr( v, buf, BUF_SIZE );
2172 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002173}
2174
2175
2176void XMLPrinter::PushAttribute( const char* name, bool v )
2177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 char buf[BUF_SIZE];
2179 XMLUtil::ToStr( v, buf, BUF_SIZE );
2180 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002181}
2182
2183
2184void XMLPrinter::PushAttribute( const char* name, double v )
2185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 char buf[BUF_SIZE];
2187 XMLUtil::ToStr( v, buf, BUF_SIZE );
2188 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002189}
2190
2191
Uli Kustererca412e82014-02-01 13:35:05 +01002192void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002193{
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 --_depth;
2195 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002196
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 Print( "/>" );
2199 }
2200 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002201 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 }
2205 Print( "</%s>", name );
2206 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002207
Lee Thomason624d43f2012-10-12 10:58:48 -07002208 if ( _textDepth == _depth ) {
2209 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 }
Uli Kustererca412e82014-02-01 13:35:05 +01002211 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 Print( "\n" );
2213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002215}
2216
2217
Dmitry-Mea092bc12014-12-23 17:57:05 +03002218void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002219{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002220 if ( !_elementJustOpened ) {
2221 return;
2222 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002225}
2226
2227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002229{
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002231
Dmitry-Mea092bc12014-12-23 17:57:05 +03002232 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002234 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 }
2236 else {
2237 PrintString( text, true );
2238 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002239}
2240
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002241void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 char buf[BUF_SIZE];
2244 XMLUtil::ToStr( value, buf, BUF_SIZE );
2245 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002246}
2247
2248
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002249void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 char buf[BUF_SIZE];
2252 XMLUtil::ToStr( value, buf, BUF_SIZE );
2253 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002254}
2255
2256
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002257void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 char buf[BUF_SIZE];
2260 XMLUtil::ToStr( value, buf, BUF_SIZE );
2261 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002262}
2263
2264
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002265void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 char buf[BUF_SIZE];
2268 XMLUtil::ToStr( value, buf, BUF_SIZE );
2269 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002270}
2271
2272
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002273void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 char buf[BUF_SIZE];
2276 XMLUtil::ToStr( value, buf, BUF_SIZE );
2277 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002278}
2279
Lee Thomason5cae8972012-01-24 18:03:07 -08002280
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002281void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002282{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002283 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002290}
Lee Thomason751da522012-02-10 08:50:51 -08002291
2292
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002293void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002295 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002296 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002298 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302}
2303
2304
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002305void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002307 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002308 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002312 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002314}
2315
2316
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002317bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002318{
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 if ( doc.HasBOM() ) {
2321 PushHeader( true, false );
2322 }
2323 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002324}
2325
2326
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002327bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002328{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002329 const XMLElement* parentElem = 0;
2330 if ( element.Parent() ) {
2331 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002332 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002333 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002334 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 while ( attribute ) {
2336 PushAttribute( attribute->Name(), attribute->Value() );
2337 attribute = attribute->Next();
2338 }
2339 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002340}
2341
2342
Uli Kustererca412e82014-02-01 13:35:05 +01002343bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002344{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002345 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002346 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002347}
2348
2349
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002350bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002352 PushText( text.Value(), text.CData() );
2353 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002354}
2355
2356
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002357bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 PushComment( comment.Value() );
2360 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002361}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002362
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002363bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 PushDeclaration( declaration.Value() );
2366 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002367}
2368
2369
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002370bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 PushUnknown( unknown.Value() );
2373 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002374}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002375
Lee Thomason685b8952012-11-12 13:00:06 -08002376} // namespace tinyxml2
2377