blob: ad3253cbf8798c0d833ddc332dcdbf1326504a52 [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 {
Dmitry-Me764545e2015-05-20 10:29:24 +0300246 bool entityFound = false;
247 for( int i = 0; 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;
Dmitry-Me764545e2015-05-20 10:29:24 +0300255 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 break;
257 }
258 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300259 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 // fixme: treat as error?
261 ++p;
262 ++q;
263 }
264 }
265 }
266 else {
267 *q = *p;
268 ++p;
269 ++q;
270 }
271 }
272 *q = 0;
273 }
274 // The loop below has plenty going on, and this
275 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 CollapseWhitespace();
278 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300281 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700282 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800283}
284
Lee Thomason2c85a712012-01-31 08:24:24 -0800285
Lee Thomasone4422302012-01-20 17:59:50 -0800286
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800287
Lee Thomason56bdd022012-02-09 18:16:58 -0800288// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800289
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290const char* XMLUtil::ReadBOM( const char* p, bool* bom )
291{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300292 TIXMLASSERT( p );
293 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 *bom = false;
295 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
296 // Check for BOM:
297 if ( *(pu+0) == TIXML_UTF_LEAD_0
298 && *(pu+1) == TIXML_UTF_LEAD_1
299 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
300 *bom = true;
301 p += 3;
302 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300303 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800305}
306
307
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800308void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 const unsigned long BYTE_MASK = 0xBF;
311 const unsigned long BYTE_MARK = 0x80;
312 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800313
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700314 if (input < 0x80) {
315 *length = 1;
316 }
317 else if ( input < 0x800 ) {
318 *length = 2;
319 }
320 else if ( input < 0x10000 ) {
321 *length = 3;
322 }
323 else if ( input < 0x200000 ) {
324 *length = 4;
325 }
326 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300327 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 return;
329 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800330
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 // Scary scary fall throughs.
334 switch (*length) {
335 case 4:
336 --output;
337 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
338 input >>= 6;
339 case 3:
340 --output;
341 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
342 input >>= 6;
343 case 2:
344 --output;
345 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
346 input >>= 6;
347 case 1:
348 --output;
349 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100350 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300351 default:
352 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800354}
355
356
357const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 // Presume an entity, and pull it out.
360 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800361
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 if ( *(p+1) == '#' && *(p+2) ) {
363 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300364 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700365 ptrdiff_t delta = 0;
366 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800367 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( *(p+2) == 'x' ) {
370 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300371 const char* q = p+3;
372 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 return 0;
374 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomason7e67bc82015-01-12 14:05:12 -0800376 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800377
Dmitry-Me9f56e122015-01-12 10:07:54 +0300378 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 return 0;
380 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800381 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 delta = q-p;
384 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700387 unsigned int digit = 0;
388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300390 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 }
392 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300393 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 }
395 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300396 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 }
398 else {
399 return 0;
400 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300401 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300402 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
403 const unsigned int digitScaled = mult * digit;
404 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
405 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300406 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 mult *= 16;
408 --q;
409 }
410 }
411 else {
412 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300413 const char* q = p+2;
414 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700415 return 0;
416 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800417
Lee Thomason7e67bc82015-01-12 14:05:12 -0800418 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800419
Dmitry-Me9f56e122015-01-12 10:07:54 +0300420 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 return 0;
422 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800423 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 delta = q-p;
426 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 while ( *q != '#' ) {
429 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300430 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300431 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300432 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
433 const unsigned int digitScaled = mult * digit;
434 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
435 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 }
437 else {
438 return 0;
439 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300440 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 mult *= 10;
442 --q;
443 }
444 }
445 // convert the UCS to UTF-8
446 ConvertUTF32ToUTF8( ucs, value, length );
447 return p + delta + 1;
448 }
449 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800450}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800451
452
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700453void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700456}
457
458
459void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700462}
463
464
465void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700468}
469
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800470/*
471 ToStr() of a number is a very tricky topic.
472 https://github.com/leethomason/tinyxml2/issues/106
473*/
Lee Thomason21be8822012-07-15 17:27:22 -0700474void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
475{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800476 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
479
480void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
481{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800482 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700483}
484
485
486bool XMLUtil::ToInt( const char* str, int* value )
487{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
489 return true;
490 }
491 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700492}
493
494bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
497 return true;
498 }
499 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700500}
501
502bool XMLUtil::ToBool( const char* str, bool* value )
503{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 int ival = 0;
505 if ( ToInt( str, &ival )) {
506 *value = (ival==0) ? false : true;
507 return true;
508 }
509 if ( StringEqual( str, "true" ) ) {
510 *value = true;
511 return true;
512 }
513 else if ( StringEqual( str, "false" ) ) {
514 *value = false;
515 return true;
516 }
517 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700518}
519
520
521bool XMLUtil::ToFloat( const char* str, float* value )
522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
524 return true;
525 }
526 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700527}
528
529bool XMLUtil::ToDouble( const char* str, double* value )
530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
532 return true;
533 }
534 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700535}
536
537
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700538char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800539{
Dmitry-Me02384662015-03-03 16:02:13 +0300540 TIXMLASSERT( node );
541 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400542 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300544 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300545 *node = 0;
546 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 return p;
548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800549
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800551 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 static const char* xmlHeader = { "<?" };
553 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300555 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800557
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 static const int xmlHeaderLen = 2;
559 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300561 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
565 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400566 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
570 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p += xmlHeaderLen;
572 }
573 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300574 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700575 returnNode = new (_commentPool.Alloc()) XMLComment( this );
576 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 p += commentHeaderLen;
578 }
579 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300580 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700583 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 p += cdataHeaderLen;
585 text->SetCData( true );
586 }
587 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300588 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700589 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
590 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 p += dtdHeaderLen;
592 }
593 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300594 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 returnNode = new (_elementPool.Alloc()) XMLElement( this );
596 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 p += elementHeaderLen;
598 }
599 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300600 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 returnNode = new (_textPool.Alloc()) XMLText( this );
602 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 p = start; // Back it up, all the text counts.
604 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605
Dmitry-Me02384662015-03-03 16:02:13 +0300606 TIXMLASSERT( returnNode );
607 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 *node = returnNode;
609 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800610}
611
612
Lee Thomason751da522012-02-10 08:50:51 -0800613bool XMLDocument::Accept( XMLVisitor* visitor ) const
614{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300615 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 if ( visitor->VisitEnter( *this ) ) {
617 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
618 if ( !node->Accept( visitor ) ) {
619 break;
620 }
621 }
622 }
623 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800624}
Lee Thomason56bdd022012-02-09 18:16:58 -0800625
626
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627// --------- XMLNode ----------- //
628
629XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 _document( doc ),
631 _parent( 0 ),
632 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200633 _prev( 0 ), _next( 0 ),
634 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800636}
637
638
639XMLNode::~XMLNode()
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( _parent ) {
643 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800645}
646
Michael Daumling21626882013-10-22 17:03:37 +0200647const char* XMLNode::Value() const
648{
649 return _value.GetStr();
650}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800651
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800652void XMLNode::SetValue( const char* str, bool staticMem )
653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 }
657 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800660}
661
662
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800663void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800664{
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300666 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300667 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700670
Dmitry-Mee3225b12014-09-03 11:03:11 +0400671 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800674}
675
676
677void XMLNode::Unlink( XMLNode* child )
678{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300679 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300680 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300681 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 if ( child == _firstChild ) {
683 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 if ( child == _lastChild ) {
686 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
Lee Thomasond923c672012-01-23 08:44:25 -0800688
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 if ( child->_prev ) {
690 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 if ( child->_next ) {
693 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700695 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800696}
697
698
U-Stream\Leeae25a442012-02-17 17:48:16 -0800699void XMLNode::DeleteChild( XMLNode* node )
700{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300701 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300702 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400704 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800705}
706
707
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800708XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
709{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300710 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300711 if ( addThis->_document != _document ) {
712 TIXMLASSERT( false );
713 return 0;
714 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800715 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 if ( _lastChild ) {
718 TIXMLASSERT( _firstChild );
719 TIXMLASSERT( _lastChild->_next == 0 );
720 _lastChild->_next = addThis;
721 addThis->_prev = _lastChild;
722 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 }
726 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 TIXMLASSERT( _firstChild == 0 );
728 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800729
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 addThis->_prev = 0;
731 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735}
736
737
Lee Thomason1ff38e02012-02-14 18:18:16 -0800738XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
739{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300740 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 if ( addThis->_document != _document ) {
742 TIXMLASSERT( false );
743 return 0;
744 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800745 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( _firstChild ) {
748 TIXMLASSERT( _lastChild );
749 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 _firstChild->_prev = addThis;
752 addThis->_next = _firstChild;
753 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800754
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 }
757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 TIXMLASSERT( _lastChild == 0 );
759 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800760
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 addThis->_prev = 0;
762 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400765 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800766}
767
768
769XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
770{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300771 TIXMLASSERT( addThis );
772 if ( addThis->_document != _document ) {
773 TIXMLASSERT( false );
774 return 0;
775 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700776
Dmitry-Meabb2d042014-12-09 12:59:31 +0300777 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700778
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300780 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 return 0;
782 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800783
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 // The last node or the only node.
786 return InsertEndChild( addThis );
787 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800788 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 addThis->_prev = afterThis;
790 addThis->_next = afterThis->_next;
791 afterThis->_next->_prev = addThis;
792 afterThis->_next = addThis;
793 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800795}
796
797
798
799
Lee Thomason56bdd022012-02-09 18:16:58 -0800800const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800801{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300802 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
803 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 if ( element ) {
805 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
806 return element;
807 }
808 }
809 }
810 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800811}
812
813
Lee Thomason56bdd022012-02-09 18:16:58 -0800814const XMLElement* XMLNode::LastChildElement( const char* value ) const
815{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300816 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
817 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 if ( element ) {
819 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
820 return element;
821 }
822 }
823 }
824 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800825}
826
827
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800828const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
829{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300830 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400831 const XMLElement* element = node->ToElement();
832 if ( element
833 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
834 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
836 }
837 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800838}
839
840
841const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
842{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300843 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400844 const XMLElement* element = node->ToElement();
845 if ( element
846 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
847 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 }
849 }
850 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800851}
852
853
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800854char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800855{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 // This is a recursive method, but thinking about it "at the current level"
857 // it is a pretty simple flat list:
858 // <foo/>
859 // <!-- comment -->
860 //
861 // With a special case:
862 // <foo>
863 // </foo>
864 // <!-- comment -->
865 //
866 // Where the closing element (/foo) *must* be the next thing after the opening
867 // element, and the names must match. BUT the tricky bit is that the closing
868 // element will be read by the child.
869 //
870 // 'endTag' is the end tag for this node, it is returned by a call to a child.
871 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800872
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 while( p && *p ) {
874 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300877 if ( node == 0 ) {
878 break;
879 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800880
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 StrPair endTag;
882 p = node->ParseDeep( p, &endTag );
883 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400884 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 if ( !_document->Error() ) {
886 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 break;
889 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800890
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400891 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500893 // We read the end tag. Return it to the parent.
894 if ( ele->ClosingType() == XMLElement::CLOSING ) {
895 if ( parentEnd ) {
896 ele->_value.TransferTo( parentEnd );
897 }
898 node->_memPool->SetTracked(); // created and then immediately deleted.
899 DeleteNode( node );
900 return p;
901 }
902
903 // Handle an end tag returned to this level.
904 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400905 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300906 if ( endTag.Empty() ) {
907 if ( ele->ClosingType() == XMLElement::OPEN ) {
908 mismatch = true;
909 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700910 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300911 else {
912 if ( ele->ClosingType() != XMLElement::OPEN ) {
913 mismatch = true;
914 }
915 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400916 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 }
918 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400919 if ( mismatch ) {
920 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500921 DeleteNode( node );
922 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400923 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
JayXondbfdd8f2014-12-12 20:07:14 -0500925 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 }
927 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800928}
929
Dmitry-Mee3225b12014-09-03 11:03:11 +0400930void XMLNode::DeleteNode( XMLNode* node )
931{
932 if ( node == 0 ) {
933 return;
934 }
935 MemPool* pool = node->_memPool;
936 node->~XMLNode();
937 pool->Free( node );
938}
939
Lee Thomason3cebdc42015-01-05 17:16:28 -0800940void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300941{
942 TIXMLASSERT( insertThis );
943 TIXMLASSERT( insertThis->_document == _document );
944
945 if ( insertThis->_parent )
946 insertThis->_parent->Unlink( insertThis );
947 else
948 insertThis->_memPool->SetTracked();
949}
950
Lee Thomason5492a1c2012-01-23 15:32:10 -0800951// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800952char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 const char* start = p;
955 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700956 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700958 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 }
960 return p;
961 }
962 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700963 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
964 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 flags |= StrPair::COLLAPSE_WHITESPACE;
966 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700967
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 if ( p && *p ) {
970 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300971 }
972 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300973 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 }
975 }
976 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800977}
978
979
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800980XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
986 text->SetCData( this->CData() );
987 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800988}
989
990
991bool XMLText::ShallowEqual( const XMLNode* compare ) const
992{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400993 const XMLText* text = compare->ToText();
994 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995}
996
997
Lee Thomason56bdd022012-02-09 18:16:58 -0800998bool XMLText::Accept( XMLVisitor* visitor ) const
999{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001000 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001002}
1003
1004
Lee Thomason3f57d272012-01-11 15:30:03 -08001005// --------- XMLComment ---------- //
1006
Lee Thomasone4422302012-01-20 17:59:50 -08001007XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001008{
1009}
1010
1011
Lee Thomasonce0763e2012-01-11 15:43:54 -08001012XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001013{
Lee Thomason3f57d272012-01-11 15:30:03 -08001014}
1015
1016
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001017char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001018{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 // Comment parses as text.
1020 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001023 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 }
1025 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001026}
1027
1028
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001029XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1030{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001032 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 }
1034 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1035 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001036}
1037
1038
1039bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1040{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001041 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001042 const XMLComment* comment = compare->ToComment();
1043 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044}
1045
1046
Lee Thomason751da522012-02-10 08:50:51 -08001047bool XMLComment::Accept( XMLVisitor* visitor ) const
1048{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001049 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001051}
Lee Thomason56bdd022012-02-09 18:16:58 -08001052
1053
Lee Thomason50f97b22012-02-11 16:33:40 -08001054// --------- XMLDeclaration ---------- //
1055
1056XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1057{
1058}
1059
1060
1061XMLDeclaration::~XMLDeclaration()
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
1066
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001067char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 // Declaration parses as text.
1070 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001071 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001073 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
1075 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001076}
1077
1078
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001079XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001082 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 }
1084 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1085 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001086}
1087
1088
1089bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1090{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001091 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001092 const XMLDeclaration* declaration = compare->ToDeclaration();
1093 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094}
1095
1096
1097
Lee Thomason50f97b22012-02-11 16:33:40 -08001098bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1099{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001100 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001102}
1103
1104// --------- XMLUnknown ---------- //
1105
1106XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1107{
1108}
1109
1110
1111XMLUnknown::~XMLUnknown()
1112{
1113}
1114
1115
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001116char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 // Unknown parses as text.
1119 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001120
Lee Thomason624d43f2012-10-12 10:58:48 -07001121 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001123 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001124 }
1125 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001126}
1127
1128
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001129XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001132 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 }
1134 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1135 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001136}
1137
1138
1139bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1140{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001141 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001142 const XMLUnknown* unknown = compare->ToUnknown();
1143 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001144}
1145
1146
Lee Thomason50f97b22012-02-11 16:33:40 -08001147bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1148{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001149 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001151}
1152
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001153// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001154
1155const char* XMLAttribute::Name() const
1156{
1157 return _name.GetStr();
1158}
1159
1160const char* XMLAttribute::Value() const
1161{
1162 return _value.GetStr();
1163}
1164
Lee Thomason6f381b72012-03-02 12:59:39 -08001165char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001168 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 if ( !p || !*p ) {
1170 return 0;
1171 }
Lee Thomason22aead12012-01-23 13:29:35 -08001172
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 // Skip white space before =
1174 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001175 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 return 0;
1177 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001178
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 ++p; // move up to opening quote
1180 p = XMLUtil::SkipWhiteSpace( p );
1181 if ( *p != '\"' && *p != '\'' ) {
1182 return 0;
1183 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001184
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 char endTag[2] = { *p, 0 };
1186 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001187
Lee Thomason624d43f2012-10-12 10:58:48 -07001188 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001190}
1191
1192
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001193void XMLAttribute::SetName( const char* n )
1194{
Lee Thomason624d43f2012-10-12 10:58:48 -07001195 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001196}
1197
1198
Lee Thomason2fa81722012-11-09 12:37:46 -08001199XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 if ( XMLUtil::ToInt( Value(), value )) {
1202 return XML_NO_ERROR;
1203 }
1204 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205}
1206
1207
Lee Thomason2fa81722012-11-09 12:37:46 -08001208XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 if ( XMLUtil::ToUnsigned( Value(), value )) {
1211 return XML_NO_ERROR;
1212 }
1213 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214}
1215
1216
Lee Thomason2fa81722012-11-09 12:37:46 -08001217XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 if ( XMLUtil::ToBool( Value(), value )) {
1220 return XML_NO_ERROR;
1221 }
1222 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001223}
1224
1225
Lee Thomason2fa81722012-11-09 12:37:46 -08001226XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 if ( XMLUtil::ToFloat( Value(), value )) {
1229 return XML_NO_ERROR;
1230 }
1231 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001232}
1233
1234
Lee Thomason2fa81722012-11-09 12:37:46 -08001235XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 if ( XMLUtil::ToDouble( Value(), value )) {
1238 return XML_NO_ERROR;
1239 }
1240 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001241}
1242
1243
1244void XMLAttribute::SetAttribute( const char* v )
1245{
Lee Thomason624d43f2012-10-12 10:58:48 -07001246 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001247}
1248
1249
Lee Thomason1ff38e02012-02-14 18:18:16 -08001250void XMLAttribute::SetAttribute( int v )
1251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 char buf[BUF_SIZE];
1253 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001255}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001256
1257
1258void XMLAttribute::SetAttribute( unsigned v )
1259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 char buf[BUF_SIZE];
1261 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001263}
1264
1265
1266void XMLAttribute::SetAttribute( bool v )
1267{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 char buf[BUF_SIZE];
1269 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001270 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001271}
1272
1273void XMLAttribute::SetAttribute( double v )
1274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 char buf[BUF_SIZE];
1276 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001277 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001278}
1279
1280void XMLAttribute::SetAttribute( float v )
1281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 char buf[BUF_SIZE];
1283 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001284 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001285}
1286
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001287
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001288// --------- XMLElement ---------- //
1289XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001290 _closingType( 0 ),
1291 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001292{
1293}
1294
1295
1296XMLElement::~XMLElement()
1297{
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 while( _rootAttribute ) {
1299 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001300 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001303}
1304
1305
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001306const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1307{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001308 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1310 return a;
1311 }
1312 }
1313 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001314}
1315
1316
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001317const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 const XMLAttribute* a = FindAttribute( name );
1320 if ( !a ) {
1321 return 0;
1322 }
1323 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1324 return a->Value();
1325 }
1326 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001327}
1328
1329
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001330const char* XMLElement::GetText() const
1331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001333 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 }
1335 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001336}
1337
1338
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001339void XMLElement::SetText( const char* inText )
1340{
Uli Kusterer869bb592014-01-21 01:36:16 +01001341 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001342 FirstChild()->SetValue( inText );
1343 else {
1344 XMLText* theText = GetDocument()->NewText( inText );
1345 InsertFirstChild( theText );
1346 }
1347}
1348
Lee Thomason5bb2d802014-01-24 10:42:57 -08001349
1350void XMLElement::SetText( int v )
1351{
1352 char buf[BUF_SIZE];
1353 XMLUtil::ToStr( v, buf, BUF_SIZE );
1354 SetText( buf );
1355}
1356
1357
1358void XMLElement::SetText( unsigned v )
1359{
1360 char buf[BUF_SIZE];
1361 XMLUtil::ToStr( v, buf, BUF_SIZE );
1362 SetText( buf );
1363}
1364
1365
1366void XMLElement::SetText( bool v )
1367{
1368 char buf[BUF_SIZE];
1369 XMLUtil::ToStr( v, buf, BUF_SIZE );
1370 SetText( buf );
1371}
1372
1373
1374void XMLElement::SetText( float v )
1375{
1376 char buf[BUF_SIZE];
1377 XMLUtil::ToStr( v, buf, BUF_SIZE );
1378 SetText( buf );
1379}
1380
1381
1382void XMLElement::SetText( double v )
1383{
1384 char buf[BUF_SIZE];
1385 XMLUtil::ToStr( v, buf, BUF_SIZE );
1386 SetText( buf );
1387}
1388
1389
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001393 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001394 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 return XML_SUCCESS;
1396 }
1397 return XML_CAN_NOT_CONVERT_TEXT;
1398 }
1399 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001400}
1401
1402
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001406 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 return XML_SUCCESS;
1409 }
1410 return XML_CAN_NOT_CONVERT_TEXT;
1411 }
1412 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001413}
1414
1415
MortenMacFly4ee49f12013-01-14 20:03:14 +01001416XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001419 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001420 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 return XML_SUCCESS;
1422 }
1423 return XML_CAN_NOT_CONVERT_TEXT;
1424 }
1425 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001426}
1427
1428
MortenMacFly4ee49f12013-01-14 20:03:14 +01001429XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001432 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001433 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 return XML_SUCCESS;
1435 }
1436 return XML_CAN_NOT_CONVERT_TEXT;
1437 }
1438 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001439}
1440
1441
MortenMacFly4ee49f12013-01-14 20:03:14 +01001442XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001445 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001446 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 return XML_SUCCESS;
1448 }
1449 return XML_CAN_NOT_CONVERT_TEXT;
1450 }
1451 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001452}
1453
1454
1455
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001456XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 XMLAttribute* last = 0;
1459 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1464 break;
1465 }
1466 }
1467 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001468 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1470 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 }
1474 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 }
1477 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001478 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 }
1480 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001481}
1482
1483
U-Stream\Leeae25a442012-02-17 17:48:16 -08001484void XMLElement::DeleteAttribute( const char* name )
1485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1489 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 }
1492 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001495 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 break;
1497 }
1498 prev = a;
1499 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001500}
1501
1502
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001503char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001504{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 const char* start = p;
1506 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001507
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 // Read the attributes.
1509 while( p ) {
1510 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001511 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 return 0;
1514 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001515
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001517 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001518 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1520 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001521 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001522
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001525 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001526 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return 0;
1528 }
1529 // There is a minor bug here: if the attribute in the source xml
1530 // document is duplicated, it will not be detected and the
1531 // attribute will be doubly added. However, tracking the 'prevAttribute'
1532 // avoids re-scanning the attribute list. Preferring performance for
1533 // now, may reconsider in the future.
1534 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001538 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 }
1540 prevAttribute = attrib;
1541 }
1542 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 else if ( *p == '>' ) {
1544 ++p;
1545 break;
1546 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001547 // end of the tag
1548 else if ( *p == '/' && *(p+1) == '>' ) {
1549 _closingType = CLOSED;
1550 return p+2; // done; sealed element.
1551 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 return 0;
1555 }
1556 }
1557 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001558}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001559
Dmitry-Mee3225b12014-09-03 11:03:11 +04001560void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1561{
1562 if ( attribute == 0 ) {
1563 return;
1564 }
1565 MemPool* pool = attribute->_memPool;
1566 attribute->~XMLAttribute();
1567 pool->Free( attribute );
1568}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001569
Lee Thomason67d61312012-01-24 16:01:51 -08001570//
1571// <ele></ele>
1572// <ele>foo<b>bar</b></ele>
1573//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001574char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 // Read the element name.
1577 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001578
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 // The closing element is the </element> form. It is
1580 // parsed just like a regular element then deleted from
1581 // the DOM.
1582 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001583 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 ++p;
1585 }
Lee Thomason67d61312012-01-24 16:01:51 -08001586
Lee Thomason624d43f2012-10-12 10:58:48 -07001587 p = _value.ParseName( p );
1588 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 return 0;
1590 }
Lee Thomason67d61312012-01-24 16:01:51 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001593 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 return p;
1595 }
Lee Thomason67d61312012-01-24 16:01:51 -08001596
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 p = XMLNode::ParseDeep( p, strPair );
1598 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001599}
1600
1601
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001602
1603XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 }
1608 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1609 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1610 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1611 }
1612 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001613}
1614
1615
1616bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1617{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001618 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 const XMLElement* other = compare->ToElement();
1620 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001621
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 const XMLAttribute* a=FirstAttribute();
1623 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 while ( a && b ) {
1626 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1627 return false;
1628 }
1629 a = a->Next();
1630 b = b->Next();
1631 }
1632 if ( a || b ) {
1633 // different count
1634 return false;
1635 }
1636 return true;
1637 }
1638 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001639}
1640
1641
Lee Thomason751da522012-02-10 08:50:51 -08001642bool XMLElement::Accept( XMLVisitor* visitor ) const
1643{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001644 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1647 if ( !node->Accept( visitor ) ) {
1648 break;
1649 }
1650 }
1651 }
1652 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001653}
Lee Thomason56bdd022012-02-09 18:16:58 -08001654
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001655
Lee Thomason3f57d272012-01-11 15:30:03 -08001656// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001657
1658// Warning: List must match 'enum XMLError'
1659const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1660 "XML_SUCCESS",
1661 "XML_NO_ATTRIBUTE",
1662 "XML_WRONG_ATTRIBUTE_TYPE",
1663 "XML_ERROR_FILE_NOT_FOUND",
1664 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1665 "XML_ERROR_FILE_READ_ERROR",
1666 "XML_ERROR_ELEMENT_MISMATCH",
1667 "XML_ERROR_PARSING_ELEMENT",
1668 "XML_ERROR_PARSING_ATTRIBUTE",
1669 "XML_ERROR_IDENTIFYING_TAG",
1670 "XML_ERROR_PARSING_TEXT",
1671 "XML_ERROR_PARSING_CDATA",
1672 "XML_ERROR_PARSING_COMMENT",
1673 "XML_ERROR_PARSING_DECLARATION",
1674 "XML_ERROR_PARSING_UNKNOWN",
1675 "XML_ERROR_EMPTY_DOCUMENT",
1676 "XML_ERROR_MISMATCHED_ELEMENT",
1677 "XML_ERROR_PARSING",
1678 "XML_CAN_NOT_CONVERT_TEXT",
1679 "XML_NO_TEXT_NODE"
1680};
1681
1682
Lee Thomason624d43f2012-10-12 10:58:48 -07001683XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 _writeBOM( false ),
1686 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001687 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 _whitespace( whitespace ),
1689 _errorStr1( 0 ),
1690 _errorStr2( 0 ),
1691 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001692{
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001694}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001695
1696
Lee Thomason3f57d272012-01-11 15:30:03 -08001697XMLDocument::~XMLDocument()
1698{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001699 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001700}
1701
1702
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001703void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001704{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001705 DeleteChildren();
1706
Dmitry-Meab37df82014-11-28 12:08:36 +03001707#ifdef DEBUG
1708 const bool hadError = Error();
1709#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 _errorID = XML_NO_ERROR;
1711 _errorStr1 = 0;
1712 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001713
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 delete [] _charBuffer;
1715 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001716
1717#if 0
1718 _textPool.Trace( "text" );
1719 _elementPool.Trace( "element" );
1720 _commentPool.Trace( "comment" );
1721 _attributePool.Trace( "attribute" );
1722#endif
1723
1724#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001725 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001726 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1727 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1728 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1729 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1730 }
1731#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001732}
1733
Lee Thomason3f57d272012-01-11 15:30:03 -08001734
Lee Thomason2c85a712012-01-31 08:24:24 -08001735XMLElement* XMLDocument::NewElement( const char* name )
1736{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001737 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1739 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 ele->SetName( name );
1741 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001742}
1743
1744
Lee Thomason1ff38e02012-02-14 18:18:16 -08001745XMLComment* XMLDocument::NewComment( const char* str )
1746{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001747 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1749 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 comment->SetValue( str );
1751 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001752}
1753
1754
1755XMLText* XMLDocument::NewText( const char* str )
1756{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001757 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1759 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 text->SetValue( str );
1761 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001762}
1763
1764
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001765XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1766{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001767 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1769 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1771 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001772}
1773
1774
1775XMLUnknown* XMLDocument::NewUnknown( const char* str )
1776{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001777 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1779 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 unk->SetValue( str );
1781 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001782}
1783
Dmitry-Me01578db2014-08-19 10:18:48 +04001784static FILE* callfopen( const char* filepath, const char* mode )
1785{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001786 TIXMLASSERT( filepath );
1787 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001788#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1789 FILE* fp = 0;
1790 errno_t err = fopen_s( &fp, filepath, mode );
1791 if ( err ) {
1792 return 0;
1793 }
1794#else
1795 FILE* fp = fopen( filepath, mode );
1796#endif
1797 return fp;
1798}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001799
1800void XMLDocument::DeleteNode( XMLNode* node ) {
1801 TIXMLASSERT( node );
1802 TIXMLASSERT(node->_document == this );
1803 if (node->_parent) {
1804 node->_parent->DeleteChild( node );
1805 }
1806 else {
1807 // Isn't in the tree.
1808 // Use the parent delete.
1809 // Also, we need to mark it tracked: we 'know'
1810 // it was never used.
1811 node->_memPool->SetTracked();
1812 // Call the static XMLNode version:
1813 XMLNode::DeleteNode(node);
1814 }
1815}
1816
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001817
Lee Thomason2fa81722012-11-09 12:37:46 -08001818XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001819{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001820 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001821 FILE* fp = callfopen( filename, "rb" );
1822 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
1826 LoadFile( fp );
1827 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829}
1830
1831
Lee Thomason2fa81722012-11-09 12:37:46 -08001832XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001834 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001835
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001836 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001837 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001838 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1839 return _errorID;
1840 }
1841
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001843 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001845 if ( filelength == -1L ) {
1846 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1847 return _errorID;
1848 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001849
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001850 if ( filelength >= (size_t)-1 ) {
1851 // Cannot handle files which won't fit in buffer together with null terminator
1852 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1853 return _errorID;
1854 }
1855
Dmitry-Me72801b82015-05-07 09:41:39 +03001856 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001857 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001860
Dmitry-Me72801b82015-05-07 09:41:39 +03001861 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 _charBuffer = new char[size+1];
1863 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 if ( read != size ) {
1865 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001868
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001870
Dmitry-Me97476b72015-01-01 16:15:57 +03001871 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001873}
1874
1875
Lee Thomason2fa81722012-11-09 12:37:46 -08001876XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001877{
Dmitry-Me01578db2014-08-19 10:18:48 +04001878 FILE* fp = callfopen( filename, "w" );
1879 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 }
1883 SaveFile(fp, compact);
1884 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001886}
1887
1888
Lee Thomason2fa81722012-11-09 12:37:46 -08001889XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001890{
Ant Mitchell189198f2015-03-24 16:20:36 +00001891 // Clear any error from the last save, otherwise it will get reported
1892 // for *this* call.
1893 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 XMLPrinter stream( fp, compact );
1895 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001897}
1898
Lee Thomason1ff38e02012-02-14 18:18:16 -08001899
Lee Thomason2fa81722012-11-09 12:37:46 -08001900XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001901{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001902 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001903
Lee Thomason82d32002014-02-21 22:47:18 -08001904 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 }
1908 if ( len == (size_t)(-1) ) {
1909 len = strlen( p );
1910 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 _charBuffer = new char[ len+1 ];
1912 memcpy( _charBuffer, p, len );
1913 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001914
Dmitry-Me97476b72015-01-01 16:15:57 +03001915 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001916 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001917 // clean up now essentially dangling memory.
1918 // and the parse fail can put objects in the
1919 // pools that are dead and inaccessible.
1920 DeleteChildren();
1921 _elementPool.Clear();
1922 _attributePool.Clear();
1923 _textPool.Clear();
1924 _commentPool.Clear();
1925 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001927}
1928
1929
PKEuS1c5f99e2013-07-06 11:28:39 +02001930void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001931{
Dmitry-Me67c429e2015-05-08 18:08:18 +03001932 if ( streamer ) {
1933 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03001935 else {
1936 XMLPrinter stdoutStreamer( stdout );
1937 Accept( &stdoutStreamer );
1938 }
Lee Thomason3f57d272012-01-11 15:30:03 -08001939}
1940
1941
Lee Thomason2fa81722012-11-09 12:37:46 -08001942void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001943{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001944 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 _errorID = error;
1946 _errorStr1 = str1;
1947 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001948}
1949
Lee Thomason331596e2014-09-11 14:56:43 -07001950const char* XMLDocument::ErrorName() const
1951{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001952 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001953 return _errorNames[_errorID];
1954}
Lee Thomason5cae8972012-01-24 18:03:07 -08001955
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001956void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001957{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001958 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 static const int LEN = 20;
1960 char buf1[LEN] = { 0 };
1961 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001962
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 if ( _errorStr1 ) {
1964 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 if ( _errorStr2 ) {
1967 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001969
Dmitry-Me2ad43202015-04-16 12:18:58 +03001970 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
1971 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
1972 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07001973 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001974 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001976}
1977
Dmitry-Me97476b72015-01-01 16:15:57 +03001978void XMLDocument::Parse()
1979{
1980 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1981 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001982 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001983 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001984 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001985 if ( !*p ) {
1986 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1987 return;
1988 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001989 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001990}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001991
PKEuS1bfb9542013-08-04 13:51:17 +02001992XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 _elementJustOpened( false ),
1994 _firstElement( true ),
1995 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001996 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 _textDepth( -1 ),
1998 _processEntities( true ),
1999 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002002 _entityFlag[i] = false;
2003 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 }
2005 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002006 const char entityValue = entities[i].value;
2007 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2008 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002010 _restrictedEntityFlag[(unsigned char)'&'] = true;
2011 _restrictedEntityFlag[(unsigned char)'<'] = true;
2012 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002014}
2015
2016
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002017void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002018{
2019 va_list va;
2020 va_start( va, format );
2021
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 if ( _fp ) {
2023 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 }
2025 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002026#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002027 #if defined(WINCE)
2028 int len = 512;
2029 do {
2030 len = len*2;
2031 char* str = new char[len]();
2032 len = _vsnprintf(str, len, format, va);
2033 delete[] str;
2034 }while (len < 0);
2035 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002036 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002037 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038#else
2039 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002040#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 // Close out and re-start the va-args
2042 va_end( va );
2043 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002044 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002045 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2046#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002047 #if defined(WINCE)
2048 _vsnprintf( p, len+1, format, va );
2049 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002050 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002051 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002052#else
2053 vsnprintf( p, len+1, format, va );
2054#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002056 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002057}
2058
2059
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002060void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 for( int i=0; i<depth; ++i ) {
2063 Print( " " );
2064 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002065}
2066
2067
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002068void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 // Look for runs of bytes between entities to print.
2071 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002072
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002074 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002076 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 // Remember, char is sometimes signed. (How many times has that bitten me?)
2078 if ( *q > 0 && *q < ENTITY_RANGE ) {
2079 // Check for entities. If one is found, flush
2080 // the stream up until the entity, write the
2081 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002082 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002084 const size_t delta = q - p;
2085 // %.*s accepts type int as "precision"
2086 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2087 Print( "%.*s", toPrint, p );
2088 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 }
2090 for( int i=0; i<NUM_ENTITIES; ++i ) {
2091 if ( entities[i].value == *q ) {
2092 Print( "&%s;", entities[i].pattern );
2093 break;
2094 }
2095 }
2096 ++p;
2097 }
2098 }
2099 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002100 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 }
2102 }
2103 // Flush the remaining string. This will be the entire
2104 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002105 TIXMLASSERT( p <= q );
2106 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 Print( "%s", p );
2108 }
Lee Thomason857b8682012-01-25 17:50:25 -08002109}
2110
U-Stream\Leeae25a442012-02-17 17:48:16 -08002111
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002112void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002115 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 -07002116 Print( "%s", bom );
2117 }
2118 if ( writeDec ) {
2119 PushDeclaration( "xml version=\"1.0\"" );
2120 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002121}
2122
2123
Uli Kusterer593a33d2014-02-01 12:48:51 +01002124void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002125{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002126 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002128
Uli Kusterer593a33d2014-02-01 12:48:51 +01002129 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002131 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002132 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002135
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 _elementJustOpened = true;
2138 _firstElement = false;
2139 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002140}
2141
2142
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002143void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002144{
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( " %s=\"", name );
2147 PrintString( value, false );
2148 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002149}
2150
2151
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002152void XMLPrinter::PushAttribute( const char* name, int v )
2153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 char buf[BUF_SIZE];
2155 XMLUtil::ToStr( v, buf, BUF_SIZE );
2156 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002157}
2158
2159
2160void XMLPrinter::PushAttribute( const char* name, unsigned v )
2161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 char buf[BUF_SIZE];
2163 XMLUtil::ToStr( v, buf, BUF_SIZE );
2164 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002165}
2166
2167
2168void XMLPrinter::PushAttribute( const char* name, bool v )
2169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 char buf[BUF_SIZE];
2171 XMLUtil::ToStr( v, buf, BUF_SIZE );
2172 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002173}
2174
2175
2176void XMLPrinter::PushAttribute( const char* name, double v )
2177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 char buf[BUF_SIZE];
2179 XMLUtil::ToStr( v, buf, BUF_SIZE );
2180 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002181}
2182
2183
Uli Kustererca412e82014-02-01 13:35:05 +01002184void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002185{
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 --_depth;
2187 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002188
Lee Thomason624d43f2012-10-12 10:58:48 -07002189 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 Print( "/>" );
2191 }
2192 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002193 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 }
2197 Print( "</%s>", name );
2198 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002199
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 if ( _textDepth == _depth ) {
2201 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 }
Uli Kustererca412e82014-02-01 13:35:05 +01002203 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "\n" );
2205 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002206 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002207}
2208
2209
Dmitry-Mea092bc12014-12-23 17:57:05 +03002210void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002211{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002212 if ( !_elementJustOpened ) {
2213 return;
2214 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002217}
2218
2219
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002220void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002221{
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002223
Dmitry-Mea092bc12014-12-23 17:57:05 +03002224 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002226 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
2228 else {
2229 PrintString( text, true );
2230 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002231}
2232
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002233void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 char buf[BUF_SIZE];
2236 XMLUtil::ToStr( value, buf, BUF_SIZE );
2237 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002238}
2239
2240
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002241void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 char buf[BUF_SIZE];
2244 XMLUtil::ToStr( value, buf, BUF_SIZE );
2245 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002246}
2247
2248
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002249void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 char buf[BUF_SIZE];
2252 XMLUtil::ToStr( value, buf, BUF_SIZE );
2253 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002254}
2255
2256
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002257void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 char buf[BUF_SIZE];
2260 XMLUtil::ToStr( value, buf, BUF_SIZE );
2261 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002262}
2263
2264
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002265void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 char buf[BUF_SIZE];
2268 XMLUtil::ToStr( value, buf, BUF_SIZE );
2269 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002270}
2271
Lee Thomason5cae8972012-01-24 18:03:07 -08002272
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002273void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002274{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002275 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002276 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002278 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002280 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002282}
Lee Thomason751da522012-02-10 08:50:51 -08002283
2284
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002285void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002286{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002287 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294}
2295
2296
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002297void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002299 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306}
2307
2308
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002309bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002310{
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 if ( doc.HasBOM() ) {
2313 PushHeader( true, false );
2314 }
2315 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002316}
2317
2318
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002319bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002320{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002321 const XMLElement* parentElem = 0;
2322 if ( element.Parent() ) {
2323 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002324 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002325 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002326 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 while ( attribute ) {
2328 PushAttribute( attribute->Name(), attribute->Value() );
2329 attribute = attribute->Next();
2330 }
2331 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002332}
2333
2334
Uli Kustererca412e82014-02-01 13:35:05 +01002335bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002336{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002337 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002339}
2340
2341
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002342bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002344 PushText( text.Value(), text.CData() );
2345 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002346}
2347
2348
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002349bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002350{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 PushComment( comment.Value() );
2352 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002353}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002354
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002355bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 PushDeclaration( declaration.Value() );
2358 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002359}
2360
2361
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002362bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 PushUnknown( unknown.Value() );
2365 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002366}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002367
Lee Thomason685b8952012-11-12 13:00:06 -08002368} // namespace tinyxml2
2369