blob: c6845dbc58f61032c61a6b1253fa1d4aab8ae275 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300231 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
232 if ( adjusted == 0 ) {
233 *q = *p;
234 ++p;
235 ++q;
236 }
237 else {
238 TIXMLASSERT( 0 <= len && len <= buflen );
239 TIXMLASSERT( q + len <= adjusted );
240 p = adjusted;
241 memcpy( q, buf, len );
242 q += len;
243 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700244 }
245 else {
246 int i=0;
247 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400248 const Entity& entity = entities[i];
249 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
250 && *( p + entity.length + 1 ) == ';' ) {
251 // Found an entity - convert.
252 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700253 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400254 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 break;
256 }
257 }
258 if ( i == NUM_ENTITIES ) {
259 // fixme: treat as error?
260 ++p;
261 ++q;
262 }
263 }
264 }
265 else {
266 *q = *p;
267 ++p;
268 ++q;
269 }
270 }
271 *q = 0;
272 }
273 // The loop below has plenty going on, and this
274 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700276 CollapseWhitespace();
277 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700279 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300280 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700281 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800282}
283
Lee Thomason2c85a712012-01-31 08:24:24 -0800284
Lee Thomasone4422302012-01-20 17:59:50 -0800285
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800286
Lee Thomason56bdd022012-02-09 18:16:58 -0800287// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800288
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800289const char* XMLUtil::ReadBOM( const char* p, bool* bom )
290{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300291 TIXMLASSERT( p );
292 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 *bom = false;
294 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
295 // Check for BOM:
296 if ( *(pu+0) == TIXML_UTF_LEAD_0
297 && *(pu+1) == TIXML_UTF_LEAD_1
298 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
299 *bom = true;
300 p += 3;
301 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300302 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304}
305
306
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800307void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 const unsigned long BYTE_MASK = 0xBF;
310 const unsigned long BYTE_MARK = 0x80;
311 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800312
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 if (input < 0x80) {
314 *length = 1;
315 }
316 else if ( input < 0x800 ) {
317 *length = 2;
318 }
319 else if ( input < 0x10000 ) {
320 *length = 3;
321 }
322 else if ( input < 0x200000 ) {
323 *length = 4;
324 }
325 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300326 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 return;
328 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800329
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800331
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Scary scary fall throughs.
333 switch (*length) {
334 case 4:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 3:
339 --output;
340 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
341 input >>= 6;
342 case 2:
343 --output;
344 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
345 input >>= 6;
346 case 1:
347 --output;
348 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100349 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300350 default:
351 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353}
354
355
356const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 // Presume an entity, and pull it out.
359 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800360
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 if ( *(p+1) == '#' && *(p+2) ) {
362 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300363 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 ptrdiff_t delta = 0;
365 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 if ( *(p+2) == 'x' ) {
369 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300370 const char* q = p+3;
371 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 return 0;
373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374
Lee Thomason7e67bc82015-01-12 14:05:12 -0800375 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800376
Dmitry-Me9f56e122015-01-12 10:07:54 +0300377 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 return 0;
379 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800380 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 delta = q-p;
383 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700386 unsigned int digit = 0;
387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300389 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 }
391 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300392 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 }
394 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300395 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 }
397 else {
398 return 0;
399 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300400 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300401 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
402 const unsigned int digitScaled = mult * digit;
403 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
404 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300405 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 mult *= 16;
407 --q;
408 }
409 }
410 else {
411 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300412 const char* q = p+2;
413 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 return 0;
415 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416
Lee Thomason7e67bc82015-01-12 14:05:12 -0800417 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800418
Dmitry-Me9f56e122015-01-12 10:07:54 +0300419 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700420 return 0;
421 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800422 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800423
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 delta = q-p;
425 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 while ( *q != '#' ) {
428 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300429 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300430 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300431 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
432 const unsigned int digitScaled = mult * digit;
433 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
434 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 }
436 else {
437 return 0;
438 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300439 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 mult *= 10;
441 --q;
442 }
443 }
444 // convert the UCS to UTF-8
445 ConvertUTF32ToUTF8( ucs, value, length );
446 return p + delta + 1;
447 }
448 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800450
451
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700452void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457
458void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700467}
468
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800469/*
470 ToStr() of a number is a very tricky topic.
471 https://github.com/leethomason/tinyxml2/issues/106
472*/
Lee Thomason21be8822012-07-15 17:27:22 -0700473void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
474{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800475 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700476}
477
478
479void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
480{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800481 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484
485bool XMLUtil::ToInt( const char* str, int* value )
486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
488 return true;
489 }
490 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700491}
492
493bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
496 return true;
497 }
498 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700499}
500
501bool XMLUtil::ToBool( const char* str, bool* value )
502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 int ival = 0;
504 if ( ToInt( str, &ival )) {
505 *value = (ival==0) ? false : true;
506 return true;
507 }
508 if ( StringEqual( str, "true" ) ) {
509 *value = true;
510 return true;
511 }
512 else if ( StringEqual( str, "false" ) ) {
513 *value = false;
514 return true;
515 }
516 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700517}
518
519
520bool XMLUtil::ToFloat( const char* str, float* value )
521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
523 return true;
524 }
525 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700526}
527
528bool XMLUtil::ToDouble( const char* str, double* value )
529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
531 return true;
532 }
533 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700537char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800538{
Dmitry-Me02384662015-03-03 16:02:13 +0300539 TIXMLASSERT( node );
540 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400541 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300543 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300544 *node = 0;
545 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 return p;
547 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800548
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 static const char* xmlHeader = { "<?" };
552 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300554 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800556
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 static const int xmlHeaderLen = 2;
558 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300560 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
564 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400565 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300567 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700568 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
569 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 p += xmlHeaderLen;
571 }
572 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300573 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700574 returnNode = new (_commentPool.Alloc()) XMLComment( this );
575 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 p += commentHeaderLen;
577 }
578 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300579 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 p += cdataHeaderLen;
584 text->SetCData( true );
585 }
586 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300587 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700588 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
589 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 p += dtdHeaderLen;
591 }
592 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300593 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 returnNode = new (_elementPool.Alloc()) XMLElement( this );
595 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 p += elementHeaderLen;
597 }
598 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300599 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700600 returnNode = new (_textPool.Alloc()) XMLText( this );
601 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 p = start; // Back it up, all the text counts.
603 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604
Dmitry-Me02384662015-03-03 16:02:13 +0300605 TIXMLASSERT( returnNode );
606 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 *node = returnNode;
608 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800609}
610
611
Lee Thomason751da522012-02-10 08:50:51 -0800612bool XMLDocument::Accept( XMLVisitor* visitor ) const
613{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300614 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 if ( visitor->VisitEnter( *this ) ) {
616 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
617 if ( !node->Accept( visitor ) ) {
618 break;
619 }
620 }
621 }
622 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800623}
Lee Thomason56bdd022012-02-09 18:16:58 -0800624
625
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800626// --------- XMLNode ----------- //
627
628XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 _document( doc ),
630 _parent( 0 ),
631 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200632 _prev( 0 ), _next( 0 ),
633 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635}
636
637
638XMLNode::~XMLNode()
639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 if ( _parent ) {
642 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800644}
645
Michael Daumling21626882013-10-22 17:03:37 +0200646const char* XMLNode::Value() const
647{
648 return _value.GetStr();
649}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800650
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800651void XMLNode::SetValue( const char* str, bool staticMem )
652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700653 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800659}
660
661
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800662void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800663{
Lee Thomason624d43f2012-10-12 10:58:48 -0700664 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300665 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300666 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700669
Dmitry-Mee3225b12014-09-03 11:03:11 +0400670 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800673}
674
675
676void XMLNode::Unlink( XMLNode* child )
677{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300678 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300679 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300680 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 if ( child == _firstChild ) {
682 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 if ( child == _lastChild ) {
685 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
Lee Thomasond923c672012-01-23 08:44:25 -0800687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( child->_prev ) {
689 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 if ( child->_next ) {
692 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700694 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695}
696
697
U-Stream\Leeae25a442012-02-17 17:48:16 -0800698void XMLNode::DeleteChild( XMLNode* node )
699{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300700 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300701 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400703 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800704}
705
706
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800707XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
708{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300709 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300710 if ( addThis->_document != _document ) {
711 TIXMLASSERT( false );
712 return 0;
713 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800714 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700715
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 if ( _lastChild ) {
717 TIXMLASSERT( _firstChild );
718 TIXMLASSERT( _lastChild->_next == 0 );
719 _lastChild->_next = addThis;
720 addThis->_prev = _lastChild;
721 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 TIXMLASSERT( _firstChild == 0 );
727 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
730 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800734}
735
736
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
738{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300739 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300740 if ( addThis->_document != _document ) {
741 TIXMLASSERT( false );
742 return 0;
743 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800744 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700745
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 if ( _firstChild ) {
747 TIXMLASSERT( _lastChild );
748 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800749
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 _firstChild->_prev = addThis;
751 addThis->_next = _firstChild;
752 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
756 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 TIXMLASSERT( _lastChild == 0 );
758 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800759
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_prev = 0;
761 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400764 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800765}
766
767
768XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
769{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300770 TIXMLASSERT( addThis );
771 if ( addThis->_document != _document ) {
772 TIXMLASSERT( false );
773 return 0;
774 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700775
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700777
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300779 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 return 0;
781 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800782
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 // The last node or the only node.
785 return InsertEndChild( addThis );
786 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800787 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 addThis->_prev = afterThis;
789 addThis->_next = afterThis->_next;
790 afterThis->_next->_prev = addThis;
791 afterThis->_next = addThis;
792 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800794}
795
796
797
798
Lee Thomason56bdd022012-02-09 18:16:58 -0800799const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800800{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300801 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
802 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 if ( element ) {
804 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
805 return element;
806 }
807 }
808 }
809 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800810}
811
812
Lee Thomason56bdd022012-02-09 18:16:58 -0800813const XMLElement* XMLNode::LastChildElement( const char* value ) const
814{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300815 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
816 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 if ( element ) {
818 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
819 return element;
820 }
821 }
822 }
823 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800824}
825
826
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800827const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
828{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300829 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400830 const XMLElement* element = node->ToElement();
831 if ( element
832 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
833 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
835 }
836 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800837}
838
839
840const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
841{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300842 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400843 const XMLElement* element = node->ToElement();
844 if ( element
845 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
846 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 }
848 }
849 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800850}
851
852
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800853char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800854{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 // This is a recursive method, but thinking about it "at the current level"
856 // it is a pretty simple flat list:
857 // <foo/>
858 // <!-- comment -->
859 //
860 // With a special case:
861 // <foo>
862 // </foo>
863 // <!-- comment -->
864 //
865 // Where the closing element (/foo) *must* be the next thing after the opening
866 // element, and the names must match. BUT the tricky bit is that the closing
867 // element will be read by the child.
868 //
869 // 'endTag' is the end tag for this node, it is returned by a call to a child.
870 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800871
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 while( p && *p ) {
873 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800874
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300876 if ( node == 0 ) {
877 break;
878 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800879
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 StrPair endTag;
881 p = node->ParseDeep( p, &endTag );
882 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400883 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 if ( !_document->Error() ) {
885 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 break;
888 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800889
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400890 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500892 // We read the end tag. Return it to the parent.
893 if ( ele->ClosingType() == XMLElement::CLOSING ) {
894 if ( parentEnd ) {
895 ele->_value.TransferTo( parentEnd );
896 }
897 node->_memPool->SetTracked(); // created and then immediately deleted.
898 DeleteNode( node );
899 return p;
900 }
901
902 // Handle an end tag returned to this level.
903 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400904 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300905 if ( endTag.Empty() ) {
906 if ( ele->ClosingType() == XMLElement::OPEN ) {
907 mismatch = true;
908 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300910 else {
911 if ( ele->ClosingType() != XMLElement::OPEN ) {
912 mismatch = true;
913 }
914 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400915 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 }
917 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400918 if ( mismatch ) {
919 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500920 DeleteNode( node );
921 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400922 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 }
JayXondbfdd8f2014-12-12 20:07:14 -0500924 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 }
926 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800927}
928
Dmitry-Mee3225b12014-09-03 11:03:11 +0400929void XMLNode::DeleteNode( XMLNode* node )
930{
931 if ( node == 0 ) {
932 return;
933 }
934 MemPool* pool = node->_memPool;
935 node->~XMLNode();
936 pool->Free( node );
937}
938
Lee Thomason3cebdc42015-01-05 17:16:28 -0800939void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300940{
941 TIXMLASSERT( insertThis );
942 TIXMLASSERT( insertThis->_document == _document );
943
944 if ( insertThis->_parent )
945 insertThis->_parent->Unlink( insertThis );
946 else
947 insertThis->_memPool->SetTracked();
948}
949
Lee Thomason5492a1c2012-01-23 15:32:10 -0800950// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800951char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 const char* start = p;
954 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700957 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 return p;
960 }
961 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700962 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
963 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 flags |= StrPair::COLLAPSE_WHITESPACE;
965 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700966
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 if ( p && *p ) {
969 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300970 }
971 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300972 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 }
974 }
975 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800976}
977
978
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800979XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 }
984 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
985 text->SetCData( this->CData() );
986 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987}
988
989
990bool XMLText::ShallowEqual( const XMLNode* compare ) const
991{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400992 const XMLText* text = compare->ToText();
993 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800994}
995
996
Lee Thomason56bdd022012-02-09 18:16:58 -0800997bool XMLText::Accept( XMLVisitor* visitor ) const
998{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300999 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001001}
1002
1003
Lee Thomason3f57d272012-01-11 15:30:03 -08001004// --------- XMLComment ---------- //
1005
Lee Thomasone4422302012-01-20 17:59:50 -08001006XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001007{
1008}
1009
1010
Lee Thomasonce0763e2012-01-11 15:43:54 -08001011XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001012{
Lee Thomason3f57d272012-01-11 15:30:03 -08001013}
1014
1015
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001016char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 // Comment parses as text.
1019 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001020 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001022 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001025}
1026
1027
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001028XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1029{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1034 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001035}
1036
1037
1038bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1039{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001040 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001041 const XMLComment* comment = compare->ToComment();
1042 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043}
1044
1045
Lee Thomason751da522012-02-10 08:50:51 -08001046bool XMLComment::Accept( XMLVisitor* visitor ) const
1047{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001048 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001050}
Lee Thomason56bdd022012-02-09 18:16:58 -08001051
1052
Lee Thomason50f97b22012-02-11 16:33:40 -08001053// --------- XMLDeclaration ---------- //
1054
1055XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1056{
1057}
1058
1059
1060XMLDeclaration::~XMLDeclaration()
1061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
1065
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001066char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001067{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 // Declaration parses as text.
1069 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 }
1074 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001075}
1076
1077
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001078XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1084 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001085}
1086
1087
1088bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1089{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001090 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001091 const XMLDeclaration* declaration = compare->ToDeclaration();
1092 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093}
1094
1095
1096
Lee Thomason50f97b22012-02-11 16:33:40 -08001097bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1098{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001099 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001101}
1102
1103// --------- XMLUnknown ---------- //
1104
1105XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1106{
1107}
1108
1109
1110XMLUnknown::~XMLUnknown()
1111{
1112}
1113
1114
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001115char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 // Unknown parses as text.
1118 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001119
Lee Thomason624d43f2012-10-12 10:58:48 -07001120 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001122 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 }
1124 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001125}
1126
1127
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001128XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 }
1133 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1134 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001135}
1136
1137
1138bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1139{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001140 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001141 const XMLUnknown* unknown = compare->ToUnknown();
1142 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001143}
1144
1145
Lee Thomason50f97b22012-02-11 16:33:40 -08001146bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1147{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001148 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001150}
1151
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001152// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001153
1154const char* XMLAttribute::Name() const
1155{
1156 return _name.GetStr();
1157}
1158
1159const char* XMLAttribute::Value() const
1160{
1161 return _value.GetStr();
1162}
1163
Lee Thomason6f381b72012-03-02 12:59:39 -08001164char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( !p || !*p ) {
1169 return 0;
1170 }
Lee Thomason22aead12012-01-23 13:29:35 -08001171
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 // Skip white space before =
1173 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001174 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 return 0;
1176 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001177
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 ++p; // move up to opening quote
1179 p = XMLUtil::SkipWhiteSpace( p );
1180 if ( *p != '\"' && *p != '\'' ) {
1181 return 0;
1182 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001183
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 char endTag[2] = { *p, 0 };
1185 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001186
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001189}
1190
1191
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001192void XMLAttribute::SetName( const char* n )
1193{
Lee Thomason624d43f2012-10-12 10:58:48 -07001194 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001195}
1196
1197
Lee Thomason2fa81722012-11-09 12:37:46 -08001198XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( XMLUtil::ToInt( Value(), value )) {
1201 return XML_NO_ERROR;
1202 }
1203 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001204}
1205
1206
Lee Thomason2fa81722012-11-09 12:37:46 -08001207XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 if ( XMLUtil::ToUnsigned( Value(), value )) {
1210 return XML_NO_ERROR;
1211 }
1212 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
1214
1215
Lee Thomason2fa81722012-11-09 12:37:46 -08001216XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 if ( XMLUtil::ToBool( Value(), value )) {
1219 return XML_NO_ERROR;
1220 }
1221 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001222}
1223
1224
Lee Thomason2fa81722012-11-09 12:37:46 -08001225XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001226{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 if ( XMLUtil::ToFloat( Value(), value )) {
1228 return XML_NO_ERROR;
1229 }
1230 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001231}
1232
1233
Lee Thomason2fa81722012-11-09 12:37:46 -08001234XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 if ( XMLUtil::ToDouble( Value(), value )) {
1237 return XML_NO_ERROR;
1238 }
1239 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001240}
1241
1242
1243void XMLAttribute::SetAttribute( const char* v )
1244{
Lee Thomason624d43f2012-10-12 10:58:48 -07001245 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001246}
1247
1248
Lee Thomason1ff38e02012-02-14 18:18:16 -08001249void XMLAttribute::SetAttribute( int v )
1250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 char buf[BUF_SIZE];
1252 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001253 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001254}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001255
1256
1257void XMLAttribute::SetAttribute( unsigned v )
1258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 char buf[BUF_SIZE];
1260 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001262}
1263
1264
1265void XMLAttribute::SetAttribute( bool v )
1266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 char buf[BUF_SIZE];
1268 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001269 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001270}
1271
1272void XMLAttribute::SetAttribute( double v )
1273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 char buf[BUF_SIZE];
1275 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001277}
1278
1279void XMLAttribute::SetAttribute( float v )
1280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 char buf[BUF_SIZE];
1282 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001283 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001284}
1285
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001286
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001287// --------- XMLElement ---------- //
1288XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001289 _closingType( 0 ),
1290 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001291{
1292}
1293
1294
1295XMLElement::~XMLElement()
1296{
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 while( _rootAttribute ) {
1298 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001299 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001300 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001302}
1303
1304
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001305const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1306{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001307 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1309 return a;
1310 }
1311 }
1312 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001313}
1314
1315
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001316const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 const XMLAttribute* a = FindAttribute( name );
1319 if ( !a ) {
1320 return 0;
1321 }
1322 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1323 return a->Value();
1324 }
1325 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001326}
1327
1328
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001329const char* XMLElement::GetText() const
1330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001332 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 }
1334 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001335}
1336
1337
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001338void XMLElement::SetText( const char* inText )
1339{
Uli Kusterer869bb592014-01-21 01:36:16 +01001340 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001341 FirstChild()->SetValue( inText );
1342 else {
1343 XMLText* theText = GetDocument()->NewText( inText );
1344 InsertFirstChild( theText );
1345 }
1346}
1347
Lee Thomason5bb2d802014-01-24 10:42:57 -08001348
1349void XMLElement::SetText( int v )
1350{
1351 char buf[BUF_SIZE];
1352 XMLUtil::ToStr( v, buf, BUF_SIZE );
1353 SetText( buf );
1354}
1355
1356
1357void XMLElement::SetText( unsigned v )
1358{
1359 char buf[BUF_SIZE];
1360 XMLUtil::ToStr( v, buf, BUF_SIZE );
1361 SetText( buf );
1362}
1363
1364
1365void XMLElement::SetText( bool v )
1366{
1367 char buf[BUF_SIZE];
1368 XMLUtil::ToStr( v, buf, BUF_SIZE );
1369 SetText( buf );
1370}
1371
1372
1373void XMLElement::SetText( float v )
1374{
1375 char buf[BUF_SIZE];
1376 XMLUtil::ToStr( v, buf, BUF_SIZE );
1377 SetText( buf );
1378}
1379
1380
1381void XMLElement::SetText( double v )
1382{
1383 char buf[BUF_SIZE];
1384 XMLUtil::ToStr( v, buf, BUF_SIZE );
1385 SetText( buf );
1386}
1387
1388
MortenMacFly4ee49f12013-01-14 20:03:14 +01001389XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001392 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return XML_SUCCESS;
1395 }
1396 return XML_CAN_NOT_CONVERT_TEXT;
1397 }
1398 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001399}
1400
1401
MortenMacFly4ee49f12013-01-14 20:03:14 +01001402XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001405 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return XML_SUCCESS;
1408 }
1409 return XML_CAN_NOT_CONVERT_TEXT;
1410 }
1411 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001412}
1413
1414
MortenMacFly4ee49f12013-01-14 20:03:14 +01001415XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001418 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001419 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 return XML_SUCCESS;
1421 }
1422 return XML_CAN_NOT_CONVERT_TEXT;
1423 }
1424 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001425}
1426
1427
MortenMacFly4ee49f12013-01-14 20:03:14 +01001428XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001431 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001432 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 return XML_SUCCESS;
1434 }
1435 return XML_CAN_NOT_CONVERT_TEXT;
1436 }
1437 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001438}
1439
1440
MortenMacFly4ee49f12013-01-14 20:03:14 +01001441XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001444 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001445 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 return XML_SUCCESS;
1447 }
1448 return XML_CAN_NOT_CONVERT_TEXT;
1449 }
1450 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001451}
1452
1453
1454
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001455XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 XMLAttribute* last = 0;
1458 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1463 break;
1464 }
1465 }
1466 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001467 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1469 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 }
1473 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 }
1476 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001477 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 }
1479 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001480}
1481
1482
U-Stream\Leeae25a442012-02-17 17:48:16 -08001483void XMLElement::DeleteAttribute( const char* name )
1484{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1488 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 }
1491 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001494 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 break;
1496 }
1497 prev = a;
1498 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001499}
1500
1501
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001502char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001503{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 const char* start = p;
1505 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001506
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 // Read the attributes.
1508 while( p ) {
1509 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001510 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return 0;
1513 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001514
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001516 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001517 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1519 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001520 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001521
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001524 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001525 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 return 0;
1527 }
1528 // There is a minor bug here: if the attribute in the source xml
1529 // document is duplicated, it will not be detected and the
1530 // attribute will be doubly added. However, tracking the 'prevAttribute'
1531 // avoids re-scanning the attribute list. Preferring performance for
1532 // now, may reconsider in the future.
1533 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001534 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 }
1536 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 }
1539 prevAttribute = attrib;
1540 }
1541 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 else if ( *p == '>' ) {
1543 ++p;
1544 break;
1545 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001546 // end of the tag
1547 else if ( *p == '/' && *(p+1) == '>' ) {
1548 _closingType = CLOSED;
1549 return p+2; // done; sealed element.
1550 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 return 0;
1554 }
1555 }
1556 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001557}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001558
Dmitry-Mee3225b12014-09-03 11:03:11 +04001559void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1560{
1561 if ( attribute == 0 ) {
1562 return;
1563 }
1564 MemPool* pool = attribute->_memPool;
1565 attribute->~XMLAttribute();
1566 pool->Free( attribute );
1567}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001568
Lee Thomason67d61312012-01-24 16:01:51 -08001569//
1570// <ele></ele>
1571// <ele>foo<b>bar</b></ele>
1572//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001573char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 // Read the element name.
1576 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001577
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 // The closing element is the </element> form. It is
1579 // parsed just like a regular element then deleted from
1580 // the DOM.
1581 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001582 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 ++p;
1584 }
Lee Thomason67d61312012-01-24 16:01:51 -08001585
Lee Thomason624d43f2012-10-12 10:58:48 -07001586 p = _value.ParseName( p );
1587 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 return 0;
1589 }
Lee Thomason67d61312012-01-24 16:01:51 -08001590
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001592 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 return p;
1594 }
Lee Thomason67d61312012-01-24 16:01:51 -08001595
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 p = XMLNode::ParseDeep( p, strPair );
1597 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001598}
1599
1600
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001601
1602XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 }
1607 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1608 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1609 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1610 }
1611 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001612}
1613
1614
1615bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1616{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001617 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 const XMLElement* other = compare->ToElement();
1619 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001620
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 const XMLAttribute* a=FirstAttribute();
1622 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001623
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 while ( a && b ) {
1625 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1626 return false;
1627 }
1628 a = a->Next();
1629 b = b->Next();
1630 }
1631 if ( a || b ) {
1632 // different count
1633 return false;
1634 }
1635 return true;
1636 }
1637 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001638}
1639
1640
Lee Thomason751da522012-02-10 08:50:51 -08001641bool XMLElement::Accept( XMLVisitor* visitor ) const
1642{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001643 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1646 if ( !node->Accept( visitor ) ) {
1647 break;
1648 }
1649 }
1650 }
1651 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001652}
Lee Thomason56bdd022012-02-09 18:16:58 -08001653
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001654
Lee Thomason3f57d272012-01-11 15:30:03 -08001655// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001656
1657// Warning: List must match 'enum XMLError'
1658const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1659 "XML_SUCCESS",
1660 "XML_NO_ATTRIBUTE",
1661 "XML_WRONG_ATTRIBUTE_TYPE",
1662 "XML_ERROR_FILE_NOT_FOUND",
1663 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1664 "XML_ERROR_FILE_READ_ERROR",
1665 "XML_ERROR_ELEMENT_MISMATCH",
1666 "XML_ERROR_PARSING_ELEMENT",
1667 "XML_ERROR_PARSING_ATTRIBUTE",
1668 "XML_ERROR_IDENTIFYING_TAG",
1669 "XML_ERROR_PARSING_TEXT",
1670 "XML_ERROR_PARSING_CDATA",
1671 "XML_ERROR_PARSING_COMMENT",
1672 "XML_ERROR_PARSING_DECLARATION",
1673 "XML_ERROR_PARSING_UNKNOWN",
1674 "XML_ERROR_EMPTY_DOCUMENT",
1675 "XML_ERROR_MISMATCHED_ELEMENT",
1676 "XML_ERROR_PARSING",
1677 "XML_CAN_NOT_CONVERT_TEXT",
1678 "XML_NO_TEXT_NODE"
1679};
1680
1681
Lee Thomason624d43f2012-10-12 10:58:48 -07001682XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 _writeBOM( false ),
1685 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001686 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 _whitespace( whitespace ),
1688 _errorStr1( 0 ),
1689 _errorStr2( 0 ),
1690 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001691{
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001693}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001694
1695
Lee Thomason3f57d272012-01-11 15:30:03 -08001696XMLDocument::~XMLDocument()
1697{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001698 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001699}
1700
1701
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001702void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001703{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001704 DeleteChildren();
1705
Dmitry-Meab37df82014-11-28 12:08:36 +03001706#ifdef DEBUG
1707 const bool hadError = Error();
1708#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 _errorID = XML_NO_ERROR;
1710 _errorStr1 = 0;
1711 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001712
Lee Thomason624d43f2012-10-12 10:58:48 -07001713 delete [] _charBuffer;
1714 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001715
1716#if 0
1717 _textPool.Trace( "text" );
1718 _elementPool.Trace( "element" );
1719 _commentPool.Trace( "comment" );
1720 _attributePool.Trace( "attribute" );
1721#endif
1722
1723#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001724 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001725 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1726 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1727 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1728 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1729 }
1730#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001731}
1732
Lee Thomason3f57d272012-01-11 15:30:03 -08001733
Lee Thomason2c85a712012-01-31 08:24:24 -08001734XMLElement* XMLDocument::NewElement( const char* name )
1735{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001736 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1738 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 ele->SetName( name );
1740 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001741}
1742
1743
Lee Thomason1ff38e02012-02-14 18:18:16 -08001744XMLComment* XMLDocument::NewComment( const char* str )
1745{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001746 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1748 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 comment->SetValue( str );
1750 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001751}
1752
1753
1754XMLText* XMLDocument::NewText( const char* str )
1755{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001756 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1758 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 text->SetValue( str );
1760 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001761}
1762
1763
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001764XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1765{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001766 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1768 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1770 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001771}
1772
1773
1774XMLUnknown* XMLDocument::NewUnknown( const char* str )
1775{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001776 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1778 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 unk->SetValue( str );
1780 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001781}
1782
Dmitry-Me01578db2014-08-19 10:18:48 +04001783static FILE* callfopen( const char* filepath, const char* mode )
1784{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001785 TIXMLASSERT( filepath );
1786 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001787#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1788 FILE* fp = 0;
1789 errno_t err = fopen_s( &fp, filepath, mode );
1790 if ( err ) {
1791 return 0;
1792 }
1793#else
1794 FILE* fp = fopen( filepath, mode );
1795#endif
1796 return fp;
1797}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001798
1799void XMLDocument::DeleteNode( XMLNode* node ) {
1800 TIXMLASSERT( node );
1801 TIXMLASSERT(node->_document == this );
1802 if (node->_parent) {
1803 node->_parent->DeleteChild( node );
1804 }
1805 else {
1806 // Isn't in the tree.
1807 // Use the parent delete.
1808 // Also, we need to mark it tracked: we 'know'
1809 // it was never used.
1810 node->_memPool->SetTracked();
1811 // Call the static XMLNode version:
1812 XMLNode::DeleteNode(node);
1813 }
1814}
1815
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001816
Lee Thomason2fa81722012-11-09 12:37:46 -08001817XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001818{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001819 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001820 FILE* fp = callfopen( filename, "rb" );
1821 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
1825 LoadFile( fp );
1826 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001828}
1829
1830
Lee Thomason2fa81722012-11-09 12:37:46 -08001831XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001833 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001835 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001836 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001837 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1838 return _errorID;
1839 }
1840
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001842 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001844 if ( filelength == -1L ) {
1845 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1846 return _errorID;
1847 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001849 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001851 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001854
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 _charBuffer = new char[size+1];
1856 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 if ( read != size ) {
1858 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001861
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001863
Dmitry-Me97476b72015-01-01 16:15:57 +03001864 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001866}
1867
1868
Lee Thomason2fa81722012-11-09 12:37:46 -08001869XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001870{
Dmitry-Me01578db2014-08-19 10:18:48 +04001871 FILE* fp = callfopen( filename, "w" );
1872 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 }
1876 SaveFile(fp, compact);
1877 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001879}
1880
1881
Lee Thomason2fa81722012-11-09 12:37:46 -08001882XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001883{
Ant Mitchell189198f2015-03-24 16:20:36 +00001884 // Clear any error from the last save, otherwise it will get reported
1885 // for *this* call.
1886 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 XMLPrinter stream( fp, compact );
1888 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001889 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001890}
1891
Lee Thomason1ff38e02012-02-14 18:18:16 -08001892
Lee Thomason2fa81722012-11-09 12:37:46 -08001893XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001894{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001895 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001896
Lee Thomason82d32002014-02-21 22:47:18 -08001897 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 }
1901 if ( len == (size_t)(-1) ) {
1902 len = strlen( p );
1903 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 _charBuffer = new char[ len+1 ];
1905 memcpy( _charBuffer, p, len );
1906 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001907
Dmitry-Me97476b72015-01-01 16:15:57 +03001908 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001909 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001910 // clean up now essentially dangling memory.
1911 // and the parse fail can put objects in the
1912 // pools that are dead and inaccessible.
1913 DeleteChildren();
1914 _elementPool.Clear();
1915 _attributePool.Clear();
1916 _textPool.Clear();
1917 _commentPool.Clear();
1918 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001920}
1921
1922
PKEuS1c5f99e2013-07-06 11:28:39 +02001923void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001924{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 XMLPrinter stdStreamer( stdout );
1926 if ( !streamer ) {
1927 streamer = &stdStreamer;
1928 }
1929 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001930}
1931
1932
Lee Thomason2fa81722012-11-09 12:37:46 -08001933void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001934{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001935 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 _errorID = error;
1937 _errorStr1 = str1;
1938 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001939}
1940
Lee Thomason331596e2014-09-11 14:56:43 -07001941const char* XMLDocument::ErrorName() const
1942{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001943 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001944 return _errorNames[_errorID];
1945}
Lee Thomason5cae8972012-01-24 18:03:07 -08001946
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001947void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001948{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001949 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 static const int LEN = 20;
1951 char buf1[LEN] = { 0 };
1952 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001953
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 if ( _errorStr1 ) {
1955 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001957 if ( _errorStr2 ) {
1958 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001960
Lee Thomason331596e2014-09-11 14:56:43 -07001961 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001962 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001964}
1965
Dmitry-Me97476b72015-01-01 16:15:57 +03001966void XMLDocument::Parse()
1967{
1968 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1969 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001970 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001971 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001972 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001973 if ( !*p ) {
1974 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1975 return;
1976 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001977 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001978}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001979
PKEuS1bfb9542013-08-04 13:51:17 +02001980XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 _elementJustOpened( false ),
1982 _firstElement( true ),
1983 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001984 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 _textDepth( -1 ),
1986 _processEntities( true ),
1987 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001990 _entityFlag[i] = false;
1991 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 }
1993 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001994 const char entityValue = entities[i].value;
1995 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1996 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001998 _restrictedEntityFlag[(unsigned char)'&'] = true;
1999 _restrictedEntityFlag[(unsigned char)'<'] = true;
2000 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002002}
2003
2004
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002005void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002006{
2007 va_list va;
2008 va_start( va, format );
2009
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 if ( _fp ) {
2011 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 }
2013 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002014#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002015 #if defined(WINCE)
2016 int len = 512;
2017 do {
2018 len = len*2;
2019 char* str = new char[len]();
2020 len = _vsnprintf(str, len, format, va);
2021 delete[] str;
2022 }while (len < 0);
2023 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002024 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002025 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026#else
2027 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002028#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 // Close out and re-start the va-args
2030 va_end( va );
2031 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002032 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002033 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2034#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002035 #if defined(WINCE)
2036 _vsnprintf( p, len+1, format, va );
2037 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002038 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002039 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002040#else
2041 vsnprintf( p, len+1, format, va );
2042#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002044 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002045}
2046
2047
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002048void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 for( int i=0; i<depth; ++i ) {
2051 Print( " " );
2052 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002053}
2054
2055
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002056void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 // Look for runs of bytes between entities to print.
2059 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002060
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002062 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 while ( *q ) {
2064 // Remember, char is sometimes signed. (How many times has that bitten me?)
2065 if ( *q > 0 && *q < ENTITY_RANGE ) {
2066 // Check for entities. If one is found, flush
2067 // the stream up until the entity, write the
2068 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002069 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002071 const size_t delta = q - p;
2072 // %.*s accepts type int as "precision"
2073 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2074 Print( "%.*s", toPrint, p );
2075 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 }
2077 for( int i=0; i<NUM_ENTITIES; ++i ) {
2078 if ( entities[i].value == *q ) {
2079 Print( "&%s;", entities[i].pattern );
2080 break;
2081 }
2082 }
2083 ++p;
2084 }
2085 }
2086 ++q;
2087 }
2088 }
2089 // Flush the remaining string. This will be the entire
2090 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 Print( "%s", p );
2093 }
Lee Thomason857b8682012-01-25 17:50:25 -08002094}
2095
U-Stream\Leeae25a442012-02-17 17:48:16 -08002096
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002097void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002100 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 -07002101 Print( "%s", bom );
2102 }
2103 if ( writeDec ) {
2104 PushDeclaration( "xml version=\"1.0\"" );
2105 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002106}
2107
2108
Uli Kusterer593a33d2014-02-01 12:48:51 +01002109void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002110{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002111 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002113
Uli Kusterer593a33d2014-02-01 12:48:51 +01002114 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002116 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002117 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002120
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 _elementJustOpened = true;
2123 _firstElement = false;
2124 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002125}
2126
2127
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002128void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002129{
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 Print( " %s=\"", name );
2132 PrintString( value, false );
2133 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002134}
2135
2136
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002137void XMLPrinter::PushAttribute( const char* name, int v )
2138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 char buf[BUF_SIZE];
2140 XMLUtil::ToStr( v, buf, BUF_SIZE );
2141 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002142}
2143
2144
2145void XMLPrinter::PushAttribute( const char* name, unsigned v )
2146{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 char buf[BUF_SIZE];
2148 XMLUtil::ToStr( v, buf, BUF_SIZE );
2149 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002150}
2151
2152
2153void XMLPrinter::PushAttribute( const char* name, bool v )
2154{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 char buf[BUF_SIZE];
2156 XMLUtil::ToStr( v, buf, BUF_SIZE );
2157 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002158}
2159
2160
2161void XMLPrinter::PushAttribute( const char* name, double v )
2162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 char buf[BUF_SIZE];
2164 XMLUtil::ToStr( v, buf, BUF_SIZE );
2165 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002166}
2167
2168
Uli Kustererca412e82014-02-01 13:35:05 +01002169void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002170{
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 --_depth;
2172 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002173
Lee Thomason624d43f2012-10-12 10:58:48 -07002174 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 Print( "/>" );
2176 }
2177 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002178 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 }
2182 Print( "</%s>", name );
2183 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002184
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 if ( _textDepth == _depth ) {
2186 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 }
Uli Kustererca412e82014-02-01 13:35:05 +01002188 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 Print( "\n" );
2190 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002192}
2193
2194
Dmitry-Mea092bc12014-12-23 17:57:05 +03002195void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002196{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002197 if ( !_elementJustOpened ) {
2198 return;
2199 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002202}
2203
2204
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002205void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002206{
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002208
Dmitry-Mea092bc12014-12-23 17:57:05 +03002209 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002211 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 }
2213 else {
2214 PrintString( text, true );
2215 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002216}
2217
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002218void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 char buf[BUF_SIZE];
2221 XMLUtil::ToStr( value, buf, BUF_SIZE );
2222 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002223}
2224
2225
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002226void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 char buf[BUF_SIZE];
2229 XMLUtil::ToStr( value, buf, BUF_SIZE );
2230 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002231}
2232
2233
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002234void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 char buf[BUF_SIZE];
2237 XMLUtil::ToStr( value, buf, BUF_SIZE );
2238 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002239}
2240
2241
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002242void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 char buf[BUF_SIZE];
2245 XMLUtil::ToStr( value, buf, BUF_SIZE );
2246 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002247}
2248
2249
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002250void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 char buf[BUF_SIZE];
2253 XMLUtil::ToStr( value, buf, BUF_SIZE );
2254 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002255}
2256
Lee Thomason5cae8972012-01-24 18:03:07 -08002257
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002258void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002259{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002260 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002267}
Lee Thomason751da522012-02-10 08:50:51 -08002268
2269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002271{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002272 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002273 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002275 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002279}
2280
2281
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002282void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002283{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002284 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002291}
2292
2293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002295{
Lee Thomason624d43f2012-10-12 10:58:48 -07002296 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 if ( doc.HasBOM() ) {
2298 PushHeader( true, false );
2299 }
2300 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002301}
2302
2303
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002304bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002305{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002306 const XMLElement* parentElem = 0;
2307 if ( element.Parent() ) {
2308 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002309 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002310 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002311 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 while ( attribute ) {
2313 PushAttribute( attribute->Name(), attribute->Value() );
2314 attribute = attribute->Next();
2315 }
2316 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002317}
2318
2319
Uli Kustererca412e82014-02-01 13:35:05 +01002320bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002321{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002322 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002324}
2325
2326
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002327bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 PushText( text.Value(), text.CData() );
2330 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002331}
2332
2333
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002334bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 PushComment( comment.Value() );
2337 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002338}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002339
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002340bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 PushDeclaration( declaration.Value() );
2343 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002344}
2345
2346
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002347bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 PushUnknown( unknown.Value() );
2350 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002351}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002352
Lee Thomason685b8952012-11-12 13:00:06 -08002353} // namespace tinyxml2
2354