blob: cb68ce1145a4c55e601094e11cd7c92122ee0951 [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{
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530648 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530649 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200650 return _value.GetStr();
651}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800652
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800653void XMLNode::SetValue( const char* str, bool staticMem )
654{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
658 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800661}
662
663
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800664void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800665{
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300667 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300668 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700671
Dmitry-Mee3225b12014-09-03 11:03:11 +0400672 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800675}
676
677
678void XMLNode::Unlink( XMLNode* child )
679{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300680 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300681 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300682 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 if ( child == _firstChild ) {
684 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 if ( child == _lastChild ) {
687 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
Lee Thomasond923c672012-01-23 08:44:25 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 if ( child->_prev ) {
691 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 if ( child->_next ) {
694 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700696 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697}
698
699
U-Stream\Leeae25a442012-02-17 17:48:16 -0800700void XMLNode::DeleteChild( XMLNode* node )
701{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300702 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300703 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400705 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800706}
707
708
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800709XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
710{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300711 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300712 if ( addThis->_document != _document ) {
713 TIXMLASSERT( false );
714 return 0;
715 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800716 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 if ( _lastChild ) {
719 TIXMLASSERT( _firstChild );
720 TIXMLASSERT( _lastChild->_next == 0 );
721 _lastChild->_next = addThis;
722 addThis->_prev = _lastChild;
723 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
727 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 TIXMLASSERT( _firstChild == 0 );
729 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_prev = 0;
732 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800736}
737
738
Lee Thomason1ff38e02012-02-14 18:18:16 -0800739XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
740{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300741 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300742 if ( addThis->_document != _document ) {
743 TIXMLASSERT( false );
744 return 0;
745 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800746 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700747
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 if ( _firstChild ) {
749 TIXMLASSERT( _lastChild );
750 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 _firstChild->_prev = addThis;
753 addThis->_next = _firstChild;
754 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800755
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
758 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 TIXMLASSERT( _lastChild == 0 );
760 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800761
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 addThis->_prev = 0;
763 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400766 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800767}
768
769
770XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
771{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300772 TIXMLASSERT( addThis );
773 if ( addThis->_document != _document ) {
774 TIXMLASSERT( false );
775 return 0;
776 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700777
Dmitry-Meabb2d042014-12-09 12:59:31 +0300778 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700779
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300781 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 return 0;
783 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // The last node or the only node.
787 return InsertEndChild( addThis );
788 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800789 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 addThis->_prev = afterThis;
791 addThis->_next = afterThis->_next;
792 afterThis->_next->_prev = addThis;
793 afterThis->_next = addThis;
794 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800796}
797
798
799
800
Lee Thomason56bdd022012-02-09 18:16:58 -0800801const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800802{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300803 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
804 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 if ( element ) {
806 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
807 return element;
808 }
809 }
810 }
811 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800812}
813
814
Lee Thomason56bdd022012-02-09 18:16:58 -0800815const XMLElement* XMLNode::LastChildElement( const char* value ) const
816{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300817 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
818 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 if ( element ) {
820 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
821 return element;
822 }
823 }
824 }
825 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800826}
827
828
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800829const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
830{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300831 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400832 const XMLElement* element = node->ToElement();
833 if ( element
834 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
835 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 }
837 }
838 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800839}
840
841
842const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
843{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300844 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400845 const XMLElement* element = node->ToElement();
846 if ( element
847 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
848 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 }
850 }
851 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800852}
853
854
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800855char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800856{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 // This is a recursive method, but thinking about it "at the current level"
858 // it is a pretty simple flat list:
859 // <foo/>
860 // <!-- comment -->
861 //
862 // With a special case:
863 // <foo>
864 // </foo>
865 // <!-- comment -->
866 //
867 // Where the closing element (/foo) *must* be the next thing after the opening
868 // element, and the names must match. BUT the tricky bit is that the closing
869 // element will be read by the child.
870 //
871 // 'endTag' is the end tag for this node, it is returned by a call to a child.
872 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800873
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 while( p && *p ) {
875 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800876
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300878 if ( node == 0 ) {
879 break;
880 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800881
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 StrPair endTag;
883 p = node->ParseDeep( p, &endTag );
884 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400885 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 if ( !_document->Error() ) {
887 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 break;
890 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800891
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400892 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500894 // We read the end tag. Return it to the parent.
895 if ( ele->ClosingType() == XMLElement::CLOSING ) {
896 if ( parentEnd ) {
897 ele->_value.TransferTo( parentEnd );
898 }
899 node->_memPool->SetTracked(); // created and then immediately deleted.
900 DeleteNode( node );
901 return p;
902 }
903
904 // Handle an end tag returned to this level.
905 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400906 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300907 if ( endTag.Empty() ) {
908 if ( ele->ClosingType() == XMLElement::OPEN ) {
909 mismatch = true;
910 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300912 else {
913 if ( ele->ClosingType() != XMLElement::OPEN ) {
914 mismatch = true;
915 }
916 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400917 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
919 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400920 if ( mismatch ) {
921 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500922 DeleteNode( node );
923 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400924 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 }
JayXondbfdd8f2014-12-12 20:07:14 -0500926 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800929}
930
Dmitry-Mee3225b12014-09-03 11:03:11 +0400931void XMLNode::DeleteNode( XMLNode* node )
932{
933 if ( node == 0 ) {
934 return;
935 }
936 MemPool* pool = node->_memPool;
937 node->~XMLNode();
938 pool->Free( node );
939}
940
Lee Thomason3cebdc42015-01-05 17:16:28 -0800941void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300942{
943 TIXMLASSERT( insertThis );
944 TIXMLASSERT( insertThis->_document == _document );
945
946 if ( insertThis->_parent )
947 insertThis->_parent->Unlink( insertThis );
948 else
949 insertThis->_memPool->SetTracked();
950}
951
Lee Thomason5492a1c2012-01-23 15:32:10 -0800952// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800953char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800954{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 const char* start = p;
956 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700957 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 }
961 return p;
962 }
963 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700964 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
965 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 flags |= StrPair::COLLAPSE_WHITESPACE;
967 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700968
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 if ( p && *p ) {
971 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300972 }
973 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300974 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 }
976 }
977 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800978}
979
980
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800981XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700984 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 }
986 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
987 text->SetCData( this->CData() );
988 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989}
990
991
992bool XMLText::ShallowEqual( const XMLNode* compare ) const
993{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400994 const XMLText* text = compare->ToText();
995 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996}
997
998
Lee Thomason56bdd022012-02-09 18:16:58 -0800999bool XMLText::Accept( XMLVisitor* visitor ) const
1000{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001001 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001003}
1004
1005
Lee Thomason3f57d272012-01-11 15:30:03 -08001006// --------- XMLComment ---------- //
1007
Lee Thomasone4422302012-01-20 17:59:50 -08001008XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001009{
1010}
1011
1012
Lee Thomasonce0763e2012-01-11 15:43:54 -08001013XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001014{
Lee Thomason3f57d272012-01-11 15:30:03 -08001015}
1016
1017
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001018char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 // Comment parses as text.
1021 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001022 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001024 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 }
1026 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001027}
1028
1029
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001030XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1036 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001037}
1038
1039
1040bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1041{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001042 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001043 const XMLComment* comment = compare->ToComment();
1044 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045}
1046
1047
Lee Thomason751da522012-02-10 08:50:51 -08001048bool XMLComment::Accept( XMLVisitor* visitor ) const
1049{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001050 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001052}
Lee Thomason56bdd022012-02-09 18:16:58 -08001053
1054
Lee Thomason50f97b22012-02-11 16:33:40 -08001055// --------- XMLDeclaration ---------- //
1056
1057XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1058{
1059}
1060
1061
1062XMLDeclaration::~XMLDeclaration()
1063{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001065}
1066
1067
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001068char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 // Declaration parses as text.
1071 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 }
1076 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001077}
1078
1079
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001080XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1086 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001087}
1088
1089
1090bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1091{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001092 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001093 const XMLDeclaration* declaration = compare->ToDeclaration();
1094 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095}
1096
1097
1098
Lee Thomason50f97b22012-02-11 16:33:40 -08001099bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1100{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001101 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001103}
1104
1105// --------- XMLUnknown ---------- //
1106
1107XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1108{
1109}
1110
1111
1112XMLUnknown::~XMLUnknown()
1113{
1114}
1115
1116
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001117char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 // Unknown parses as text.
1120 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001121
Lee Thomason624d43f2012-10-12 10:58:48 -07001122 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001124 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 }
1126 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001127}
1128
1129
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001130XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001133 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 }
1135 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1136 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001137}
1138
1139
1140bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1141{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001142 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001143 const XMLUnknown* unknown = compare->ToUnknown();
1144 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001145}
1146
1147
Lee Thomason50f97b22012-02-11 16:33:40 -08001148bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1149{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001150 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001152}
1153
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001154// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001155
1156const char* XMLAttribute::Name() const
1157{
1158 return _name.GetStr();
1159}
1160
1161const char* XMLAttribute::Value() const
1162{
1163 return _value.GetStr();
1164}
1165
Lee Thomason6f381b72012-03-02 12:59:39 -08001166char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001169 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 if ( !p || !*p ) {
1171 return 0;
1172 }
Lee Thomason22aead12012-01-23 13:29:35 -08001173
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 // Skip white space before =
1175 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001176 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 return 0;
1178 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001179
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 ++p; // move up to opening quote
1181 p = XMLUtil::SkipWhiteSpace( p );
1182 if ( *p != '\"' && *p != '\'' ) {
1183 return 0;
1184 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001185
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 char endTag[2] = { *p, 0 };
1187 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001188
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001191}
1192
1193
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001194void XMLAttribute::SetName( const char* n )
1195{
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001197}
1198
1199
Lee Thomason2fa81722012-11-09 12:37:46 -08001200XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( XMLUtil::ToInt( Value(), value )) {
1203 return XML_NO_ERROR;
1204 }
1205 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001206}
1207
1208
Lee Thomason2fa81722012-11-09 12:37:46 -08001209XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 if ( XMLUtil::ToUnsigned( 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::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 if ( XMLUtil::ToBool( 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::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( XMLUtil::ToFloat( Value(), value )) {
1230 return XML_NO_ERROR;
1231 }
1232 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001233}
1234
1235
Lee Thomason2fa81722012-11-09 12:37:46 -08001236XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( XMLUtil::ToDouble( Value(), value )) {
1239 return XML_NO_ERROR;
1240 }
1241 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001242}
1243
1244
1245void XMLAttribute::SetAttribute( const char* v )
1246{
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001248}
1249
1250
Lee Thomason1ff38e02012-02-14 18:18:16 -08001251void XMLAttribute::SetAttribute( int v )
1252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 char buf[BUF_SIZE];
1254 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001256}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001257
1258
1259void XMLAttribute::SetAttribute( unsigned v )
1260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 char buf[BUF_SIZE];
1262 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001264}
1265
1266
1267void XMLAttribute::SetAttribute( bool v )
1268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 char buf[BUF_SIZE];
1270 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001271 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272}
1273
1274void XMLAttribute::SetAttribute( double v )
1275{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 char buf[BUF_SIZE];
1277 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001278 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001279}
1280
1281void XMLAttribute::SetAttribute( float v )
1282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 char buf[BUF_SIZE];
1284 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001285 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001286}
1287
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001288
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001289// --------- XMLElement ---------- //
1290XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001291 _closingType( 0 ),
1292 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001293{
1294}
1295
1296
1297XMLElement::~XMLElement()
1298{
Lee Thomason624d43f2012-10-12 10:58:48 -07001299 while( _rootAttribute ) {
1300 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001301 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001302 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001304}
1305
1306
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001307const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1308{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001309 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1311 return a;
1312 }
1313 }
1314 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001315}
1316
1317
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001318const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 const XMLAttribute* a = FindAttribute( name );
1321 if ( !a ) {
1322 return 0;
1323 }
1324 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1325 return a->Value();
1326 }
1327 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001328}
1329
1330
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001331const char* XMLElement::GetText() const
1332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001334 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 }
1336 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001337}
1338
1339
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001340void XMLElement::SetText( const char* inText )
1341{
Uli Kusterer869bb592014-01-21 01:36:16 +01001342 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001343 FirstChild()->SetValue( inText );
1344 else {
1345 XMLText* theText = GetDocument()->NewText( inText );
1346 InsertFirstChild( theText );
1347 }
1348}
1349
Lee Thomason5bb2d802014-01-24 10:42:57 -08001350
1351void XMLElement::SetText( int v )
1352{
1353 char buf[BUF_SIZE];
1354 XMLUtil::ToStr( v, buf, BUF_SIZE );
1355 SetText( buf );
1356}
1357
1358
1359void XMLElement::SetText( unsigned v )
1360{
1361 char buf[BUF_SIZE];
1362 XMLUtil::ToStr( v, buf, BUF_SIZE );
1363 SetText( buf );
1364}
1365
1366
1367void XMLElement::SetText( bool v )
1368{
1369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
1371 SetText( buf );
1372}
1373
1374
1375void XMLElement::SetText( float v )
1376{
1377 char buf[BUF_SIZE];
1378 XMLUtil::ToStr( v, buf, BUF_SIZE );
1379 SetText( buf );
1380}
1381
1382
1383void XMLElement::SetText( double v )
1384{
1385 char buf[BUF_SIZE];
1386 XMLUtil::ToStr( v, buf, BUF_SIZE );
1387 SetText( buf );
1388}
1389
1390
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001392{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001394 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 return XML_SUCCESS;
1397 }
1398 return XML_CAN_NOT_CONVERT_TEXT;
1399 }
1400 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001401}
1402
1403
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001407 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 return XML_SUCCESS;
1410 }
1411 return XML_CAN_NOT_CONVERT_TEXT;
1412 }
1413 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001414}
1415
1416
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001420 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001421 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 return XML_SUCCESS;
1423 }
1424 return XML_CAN_NOT_CONVERT_TEXT;
1425 }
1426 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001427}
1428
1429
MortenMacFly4ee49f12013-01-14 20:03:14 +01001430XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001433 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001434 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 return XML_SUCCESS;
1436 }
1437 return XML_CAN_NOT_CONVERT_TEXT;
1438 }
1439 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001440}
1441
1442
MortenMacFly4ee49f12013-01-14 20:03:14 +01001443XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001446 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001447 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 return XML_SUCCESS;
1449 }
1450 return XML_CAN_NOT_CONVERT_TEXT;
1451 }
1452 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001453}
1454
1455
1456
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001457XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 XMLAttribute* last = 0;
1460 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1465 break;
1466 }
1467 }
1468 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001469 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1471 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 }
1475 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 }
1478 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001479 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 }
1481 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001482}
1483
1484
U-Stream\Leeae25a442012-02-17 17:48:16 -08001485void XMLElement::DeleteAttribute( const char* name )
1486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1490 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 }
1493 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001494 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001496 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 break;
1498 }
1499 prev = a;
1500 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001501}
1502
1503
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001504char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 const char* start = p;
1507 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001508
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 // Read the attributes.
1510 while( p ) {
1511 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001512 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001516
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001518 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001519 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1521 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001522 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001523
Lee Thomason624d43f2012-10-12 10:58:48 -07001524 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001526 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001527 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 return 0;
1529 }
1530 // There is a minor bug here: if the attribute in the source xml
1531 // document is duplicated, it will not be detected and the
1532 // attribute will be doubly added. However, tracking the 'prevAttribute'
1533 // avoids re-scanning the attribute list. Preferring performance for
1534 // now, may reconsider in the future.
1535 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 }
1538 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 }
1541 prevAttribute = attrib;
1542 }
1543 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 else if ( *p == '>' ) {
1545 ++p;
1546 break;
1547 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001548 // end of the tag
1549 else if ( *p == '/' && *(p+1) == '>' ) {
1550 _closingType = CLOSED;
1551 return p+2; // done; sealed element.
1552 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 return 0;
1556 }
1557 }
1558 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001559}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001560
Dmitry-Mee3225b12014-09-03 11:03:11 +04001561void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1562{
1563 if ( attribute == 0 ) {
1564 return;
1565 }
1566 MemPool* pool = attribute->_memPool;
1567 attribute->~XMLAttribute();
1568 pool->Free( attribute );
1569}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001570
Lee Thomason67d61312012-01-24 16:01:51 -08001571//
1572// <ele></ele>
1573// <ele>foo<b>bar</b></ele>
1574//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001575char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 // Read the element name.
1578 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001579
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 // The closing element is the </element> form. It is
1581 // parsed just like a regular element then deleted from
1582 // the DOM.
1583 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 ++p;
1586 }
Lee Thomason67d61312012-01-24 16:01:51 -08001587
Lee Thomason624d43f2012-10-12 10:58:48 -07001588 p = _value.ParseName( p );
1589 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 return 0;
1591 }
Lee Thomason67d61312012-01-24 16:01:51 -08001592
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 return p;
1596 }
Lee Thomason67d61312012-01-24 16:01:51 -08001597
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 p = XMLNode::ParseDeep( p, strPair );
1599 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001600}
1601
1602
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001603
1604XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 }
1609 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1610 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1611 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1612 }
1613 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001614}
1615
1616
1617bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1618{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001619 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 const XMLElement* other = compare->ToElement();
1621 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001622
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 const XMLAttribute* a=FirstAttribute();
1624 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001625
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 while ( a && b ) {
1627 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1628 return false;
1629 }
1630 a = a->Next();
1631 b = b->Next();
1632 }
1633 if ( a || b ) {
1634 // different count
1635 return false;
1636 }
1637 return true;
1638 }
1639 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001640}
1641
1642
Lee Thomason751da522012-02-10 08:50:51 -08001643bool XMLElement::Accept( XMLVisitor* visitor ) const
1644{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001645 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1648 if ( !node->Accept( visitor ) ) {
1649 break;
1650 }
1651 }
1652 }
1653 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001654}
Lee Thomason56bdd022012-02-09 18:16:58 -08001655
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001656
Lee Thomason3f57d272012-01-11 15:30:03 -08001657// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001658
1659// Warning: List must match 'enum XMLError'
1660const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1661 "XML_SUCCESS",
1662 "XML_NO_ATTRIBUTE",
1663 "XML_WRONG_ATTRIBUTE_TYPE",
1664 "XML_ERROR_FILE_NOT_FOUND",
1665 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1666 "XML_ERROR_FILE_READ_ERROR",
1667 "XML_ERROR_ELEMENT_MISMATCH",
1668 "XML_ERROR_PARSING_ELEMENT",
1669 "XML_ERROR_PARSING_ATTRIBUTE",
1670 "XML_ERROR_IDENTIFYING_TAG",
1671 "XML_ERROR_PARSING_TEXT",
1672 "XML_ERROR_PARSING_CDATA",
1673 "XML_ERROR_PARSING_COMMENT",
1674 "XML_ERROR_PARSING_DECLARATION",
1675 "XML_ERROR_PARSING_UNKNOWN",
1676 "XML_ERROR_EMPTY_DOCUMENT",
1677 "XML_ERROR_MISMATCHED_ELEMENT",
1678 "XML_ERROR_PARSING",
1679 "XML_CAN_NOT_CONVERT_TEXT",
1680 "XML_NO_TEXT_NODE"
1681};
1682
1683
Lee Thomason624d43f2012-10-12 10:58:48 -07001684XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001686 _writeBOM( false ),
1687 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001688 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 _whitespace( whitespace ),
1690 _errorStr1( 0 ),
1691 _errorStr2( 0 ),
1692 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001693{
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001695}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001696
1697
Lee Thomason3f57d272012-01-11 15:30:03 -08001698XMLDocument::~XMLDocument()
1699{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001700 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001701}
1702
1703
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001704void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001705{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001706 DeleteChildren();
1707
Dmitry-Meab37df82014-11-28 12:08:36 +03001708#ifdef DEBUG
1709 const bool hadError = Error();
1710#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 _errorID = XML_NO_ERROR;
1712 _errorStr1 = 0;
1713 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001714
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 delete [] _charBuffer;
1716 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001717
1718#if 0
1719 _textPool.Trace( "text" );
1720 _elementPool.Trace( "element" );
1721 _commentPool.Trace( "comment" );
1722 _attributePool.Trace( "attribute" );
1723#endif
1724
1725#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001726 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001727 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1728 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1729 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1730 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1731 }
1732#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001733}
1734
Lee Thomason3f57d272012-01-11 15:30:03 -08001735
Lee Thomason2c85a712012-01-31 08:24:24 -08001736XMLElement* XMLDocument::NewElement( const char* name )
1737{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001738 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1740 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 ele->SetName( name );
1742 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001743}
1744
1745
Lee Thomason1ff38e02012-02-14 18:18:16 -08001746XMLComment* XMLDocument::NewComment( const char* str )
1747{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001748 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1750 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 comment->SetValue( str );
1752 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001753}
1754
1755
1756XMLText* XMLDocument::NewText( const char* str )
1757{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001758 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1760 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 text->SetValue( str );
1762 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001763}
1764
1765
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1767{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001768 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1770 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1772 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001773}
1774
1775
1776XMLUnknown* XMLDocument::NewUnknown( const char* str )
1777{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001778 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1780 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 unk->SetValue( str );
1782 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001783}
1784
Dmitry-Me01578db2014-08-19 10:18:48 +04001785static FILE* callfopen( const char* filepath, const char* mode )
1786{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001787 TIXMLASSERT( filepath );
1788 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001789#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1790 FILE* fp = 0;
1791 errno_t err = fopen_s( &fp, filepath, mode );
1792 if ( err ) {
1793 return 0;
1794 }
1795#else
1796 FILE* fp = fopen( filepath, mode );
1797#endif
1798 return fp;
1799}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001800
1801void XMLDocument::DeleteNode( XMLNode* node ) {
1802 TIXMLASSERT( node );
1803 TIXMLASSERT(node->_document == this );
1804 if (node->_parent) {
1805 node->_parent->DeleteChild( node );
1806 }
1807 else {
1808 // Isn't in the tree.
1809 // Use the parent delete.
1810 // Also, we need to mark it tracked: we 'know'
1811 // it was never used.
1812 node->_memPool->SetTracked();
1813 // Call the static XMLNode version:
1814 XMLNode::DeleteNode(node);
1815 }
1816}
1817
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001818
Lee Thomason2fa81722012-11-09 12:37:46 -08001819XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001820{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001821 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001822 FILE* fp = callfopen( filename, "rb" );
1823 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 }
1827 LoadFile( fp );
1828 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001829 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001830}
1831
1832
Lee Thomason2fa81722012-11-09 12:37:46 -08001833XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001835 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001836
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001837 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001838 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001839 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1840 return _errorID;
1841 }
1842
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001844 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001846 if ( filelength == -1L ) {
1847 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1848 return _errorID;
1849 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001850
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001851 if ( filelength >= (size_t)-1 ) {
1852 // Cannot handle files which won't fit in buffer together with null terminator
1853 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1854 return _errorID;
1855 }
1856
Dmitry-Me72801b82015-05-07 09:41:39 +03001857 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001858 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001861
Dmitry-Me72801b82015-05-07 09:41:39 +03001862 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 _charBuffer = new char[size+1];
1864 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 if ( read != size ) {
1866 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001869
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001871
Dmitry-Me97476b72015-01-01 16:15:57 +03001872 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001874}
1875
1876
Lee Thomason2fa81722012-11-09 12:37:46 -08001877XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001878{
Dmitry-Me01578db2014-08-19 10:18:48 +04001879 FILE* fp = callfopen( filename, "w" );
1880 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 SaveFile(fp, compact);
1885 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001887}
1888
1889
Lee Thomason2fa81722012-11-09 12:37:46 -08001890XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001891{
Ant Mitchell189198f2015-03-24 16:20:36 +00001892 // Clear any error from the last save, otherwise it will get reported
1893 // for *this* call.
1894 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 XMLPrinter stream( fp, compact );
1896 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001898}
1899
Lee Thomason1ff38e02012-02-14 18:18:16 -08001900
Lee Thomason2fa81722012-11-09 12:37:46 -08001901XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001902{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001903 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001904
Lee Thomason82d32002014-02-21 22:47:18 -08001905 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 }
1909 if ( len == (size_t)(-1) ) {
1910 len = strlen( p );
1911 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 _charBuffer = new char[ len+1 ];
1913 memcpy( _charBuffer, p, len );
1914 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001915
Dmitry-Me97476b72015-01-01 16:15:57 +03001916 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001917 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001918 // clean up now essentially dangling memory.
1919 // and the parse fail can put objects in the
1920 // pools that are dead and inaccessible.
1921 DeleteChildren();
1922 _elementPool.Clear();
1923 _attributePool.Clear();
1924 _textPool.Clear();
1925 _commentPool.Clear();
1926 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001927 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001928}
1929
1930
PKEuS1c5f99e2013-07-06 11:28:39 +02001931void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001932{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 XMLPrinter stdStreamer( stdout );
1934 if ( !streamer ) {
1935 streamer = &stdStreamer;
1936 }
1937 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001938}
1939
1940
Lee Thomason2fa81722012-11-09 12:37:46 -08001941void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001942{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001943 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 _errorID = error;
1945 _errorStr1 = str1;
1946 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001947}
1948
Lee Thomason331596e2014-09-11 14:56:43 -07001949const char* XMLDocument::ErrorName() const
1950{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001951 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001952 return _errorNames[_errorID];
1953}
Lee Thomason5cae8972012-01-24 18:03:07 -08001954
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001955void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001956{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001957 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 static const int LEN = 20;
1959 char buf1[LEN] = { 0 };
1960 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001961
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 if ( _errorStr1 ) {
1963 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001965 if ( _errorStr2 ) {
1966 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001968
Dmitry-Me2ad43202015-04-16 12:18:58 +03001969 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
1970 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
1971 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07001972 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001973 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001975}
1976
Dmitry-Me97476b72015-01-01 16:15:57 +03001977void XMLDocument::Parse()
1978{
1979 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1980 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001981 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001982 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001983 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001984 if ( !*p ) {
1985 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1986 return;
1987 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001988 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001989}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001990
PKEuS1bfb9542013-08-04 13:51:17 +02001991XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001992 _elementJustOpened( false ),
1993 _firstElement( true ),
1994 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001995 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001996 _textDepth( -1 ),
1997 _processEntities( true ),
1998 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _entityFlag[i] = false;
2002 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 }
2004 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002005 const char entityValue = entities[i].value;
2006 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2007 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002009 _restrictedEntityFlag[(unsigned char)'&'] = true;
2010 _restrictedEntityFlag[(unsigned char)'<'] = true;
2011 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002012 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002017{
2018 va_list va;
2019 va_start( va, format );
2020
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _fp ) {
2022 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 }
2024 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002025#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002026 #if defined(WINCE)
2027 int len = 512;
2028 do {
2029 len = len*2;
2030 char* str = new char[len]();
2031 len = _vsnprintf(str, len, format, va);
2032 delete[] str;
2033 }while (len < 0);
2034 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002035 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002036 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037#else
2038 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002039#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 // Close out and re-start the va-args
2041 va_end( va );
2042 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002043 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002044 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2045#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002046 #if defined(WINCE)
2047 _vsnprintf( p, len+1, format, va );
2048 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002049 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002050 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002051#else
2052 vsnprintf( p, len+1, format, va );
2053#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002055 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002056}
2057
2058
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002059void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002060{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 for( int i=0; i<depth; ++i ) {
2062 Print( " " );
2063 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002064}
2065
2066
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002067void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 // Look for runs of bytes between entities to print.
2070 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002071
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002073 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002075 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 // Remember, char is sometimes signed. (How many times has that bitten me?)
2077 if ( *q > 0 && *q < ENTITY_RANGE ) {
2078 // Check for entities. If one is found, flush
2079 // the stream up until the entity, write the
2080 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002081 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002083 const size_t delta = q - p;
2084 // %.*s accepts type int as "precision"
2085 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2086 Print( "%.*s", toPrint, p );
2087 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 }
2089 for( int i=0; i<NUM_ENTITIES; ++i ) {
2090 if ( entities[i].value == *q ) {
2091 Print( "&%s;", entities[i].pattern );
2092 break;
2093 }
2094 }
2095 ++p;
2096 }
2097 }
2098 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002099 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 }
2101 }
2102 // Flush the remaining string. This will be the entire
2103 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002104 TIXMLASSERT( p <= q );
2105 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 Print( "%s", p );
2107 }
Lee Thomason857b8682012-01-25 17:50:25 -08002108}
2109
U-Stream\Leeae25a442012-02-17 17:48:16 -08002110
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002111void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002114 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 -07002115 Print( "%s", bom );
2116 }
2117 if ( writeDec ) {
2118 PushDeclaration( "xml version=\"1.0\"" );
2119 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002120}
2121
2122
Uli Kusterer593a33d2014-02-01 12:48:51 +01002123void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002124{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002125 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002127
Uli Kusterer593a33d2014-02-01 12:48:51 +01002128 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002130 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002131 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002134
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 _elementJustOpened = true;
2137 _firstElement = false;
2138 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002139}
2140
2141
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002142void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002143{
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 Print( " %s=\"", name );
2146 PrintString( value, false );
2147 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002148}
2149
2150
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002151void XMLPrinter::PushAttribute( const char* name, int v )
2152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 char buf[BUF_SIZE];
2154 XMLUtil::ToStr( v, buf, BUF_SIZE );
2155 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002156}
2157
2158
2159void XMLPrinter::PushAttribute( const char* name, unsigned v )
2160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 char buf[BUF_SIZE];
2162 XMLUtil::ToStr( v, buf, BUF_SIZE );
2163 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002164}
2165
2166
2167void XMLPrinter::PushAttribute( const char* name, bool v )
2168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 char buf[BUF_SIZE];
2170 XMLUtil::ToStr( v, buf, BUF_SIZE );
2171 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002172}
2173
2174
2175void XMLPrinter::PushAttribute( const char* name, double v )
2176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 char buf[BUF_SIZE];
2178 XMLUtil::ToStr( v, buf, BUF_SIZE );
2179 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002180}
2181
2182
Uli Kustererca412e82014-02-01 13:35:05 +01002183void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002184{
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 --_depth;
2186 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002187
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 Print( "/>" );
2190 }
2191 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002192 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 }
2196 Print( "</%s>", name );
2197 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002198
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 if ( _textDepth == _depth ) {
2200 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 }
Uli Kustererca412e82014-02-01 13:35:05 +01002202 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 Print( "\n" );
2204 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002206}
2207
2208
Dmitry-Mea092bc12014-12-23 17:57:05 +03002209void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002210{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002211 if ( !_elementJustOpened ) {
2212 return;
2213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002216}
2217
2218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002220{
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002222
Dmitry-Mea092bc12014-12-23 17:57:05 +03002223 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002225 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 }
2227 else {
2228 PrintString( text, true );
2229 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002230}
2231
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002232void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 char buf[BUF_SIZE];
2235 XMLUtil::ToStr( value, buf, BUF_SIZE );
2236 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002237}
2238
2239
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002240void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 char buf[BUF_SIZE];
2243 XMLUtil::ToStr( value, buf, BUF_SIZE );
2244 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002245}
2246
2247
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002248void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 char buf[BUF_SIZE];
2251 XMLUtil::ToStr( value, buf, BUF_SIZE );
2252 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002253}
2254
2255
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002256void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 char buf[BUF_SIZE];
2259 XMLUtil::ToStr( value, buf, BUF_SIZE );
2260 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002261}
2262
2263
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002264void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002265{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 char buf[BUF_SIZE];
2267 XMLUtil::ToStr( value, buf, BUF_SIZE );
2268 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002269}
2270
Lee Thomason5cae8972012-01-24 18:03:07 -08002271
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002272void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002273{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002274 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002275 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002279 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002281}
Lee Thomason751da522012-02-10 08:50:51 -08002282
2283
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002284void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002285{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002286 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293}
2294
2295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002298 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002299 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305}
2306
2307
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002308bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002309{
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 if ( doc.HasBOM() ) {
2312 PushHeader( true, false );
2313 }
2314 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002315}
2316
2317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002319{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002320 const XMLElement* parentElem = 0;
2321 if ( element.Parent() ) {
2322 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002323 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002324 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002325 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002326 while ( attribute ) {
2327 PushAttribute( attribute->Name(), attribute->Value() );
2328 attribute = attribute->Next();
2329 }
2330 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002331}
2332
2333
Uli Kustererca412e82014-02-01 13:35:05 +01002334bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002335{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002336 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002338}
2339
2340
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002341bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002343 PushText( text.Value(), text.CData() );
2344 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002345}
2346
2347
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002348bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 PushComment( comment.Value() );
2351 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002352}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002353
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002354bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 PushDeclaration( declaration.Value() );
2357 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002358}
2359
2360
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002361bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 PushUnknown( unknown.Value() );
2364 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002365}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002366
Lee Thomason685b8952012-11-12 13:00:06 -08002367} // namespace tinyxml2
2368