blob: a22f25110eb38f26acc7bcdf983f368d472c7309 [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 = { "<!--" };
553 static const char* dtdHeader = { "<!" };
554 static const char* cdataHeader = { "<![CDATA[" };
555 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;
559 static const int dtdHeaderLen = 2;
560 static const int cdataHeaderLen = 9;
561 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-Meabb2d042014-12-09 12:59:31 +0300665 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700668
Dmitry-Mee3225b12014-09-03 11:03:11 +0400669 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800672}
673
674
675void XMLNode::Unlink( XMLNode* child )
676{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300677 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300678 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 if ( child == _firstChild ) {
680 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 if ( child == _lastChild ) {
683 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 }
Lee Thomasond923c672012-01-23 08:44:25 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 if ( child->_prev ) {
687 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 if ( child->_next ) {
690 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700692 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693}
694
695
U-Stream\Leeae25a442012-02-17 17:48:16 -0800696void XMLNode::DeleteChild( XMLNode* node )
697{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300698 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300699 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400701 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800702}
703
704
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800705XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
706{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300707 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300708 if ( addThis->_document != _document ) {
709 TIXMLASSERT( false );
710 return 0;
711 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800712 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700713
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 if ( _lastChild ) {
715 TIXMLASSERT( _firstChild );
716 TIXMLASSERT( _lastChild->_next == 0 );
717 _lastChild->_next = addThis;
718 addThis->_prev = _lastChild;
719 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 }
723 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 TIXMLASSERT( _firstChild == 0 );
725 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800726
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_prev = 0;
728 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732}
733
734
Lee Thomason1ff38e02012-02-14 18:18:16 -0800735XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
736{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300737 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300738 if ( addThis->_document != _document ) {
739 TIXMLASSERT( false );
740 return 0;
741 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800742 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700743
Lee Thomason624d43f2012-10-12 10:58:48 -0700744 if ( _firstChild ) {
745 TIXMLASSERT( _lastChild );
746 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800747
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 _firstChild->_prev = addThis;
749 addThis->_next = _firstChild;
750 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 }
754 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 TIXMLASSERT( _lastChild == 0 );
756 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800757
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 addThis->_prev = 0;
759 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400762 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800763}
764
765
766XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
767{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300768 TIXMLASSERT( addThis );
769 if ( addThis->_document != _document ) {
770 TIXMLASSERT( false );
771 return 0;
772 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700773
Dmitry-Meabb2d042014-12-09 12:59:31 +0300774 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700775
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300777 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 return 0;
779 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800780
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 // The last node or the only node.
783 return InsertEndChild( addThis );
784 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800785 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 addThis->_prev = afterThis;
787 addThis->_next = afterThis->_next;
788 afterThis->_next->_prev = addThis;
789 afterThis->_next = addThis;
790 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800792}
793
794
795
796
Lee Thomason56bdd022012-02-09 18:16:58 -0800797const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800798{
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 XMLElement* element = node->ToElement();
801 if ( element ) {
802 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
803 return element;
804 }
805 }
806 }
807 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800808}
809
810
Lee Thomason56bdd022012-02-09 18:16:58 -0800811const XMLElement* XMLNode::LastChildElement( const char* value ) const
812{
Lee Thomason624d43f2012-10-12 10:58:48 -0700813 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 XMLElement* element = node->ToElement();
815 if ( element ) {
816 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
817 return element;
818 }
819 }
820 }
821 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800822}
823
824
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800825const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
826{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400827 for( XMLNode* node=this->_next; node; node = node->_next ) {
828 const XMLElement* element = node->ToElement();
829 if ( element
830 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
831 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
833 }
834 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800835}
836
837
838const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
839{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400840 for( XMLNode* node=_prev; node; node = node->_prev ) {
841 const XMLElement* element = node->ToElement();
842 if ( element
843 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
844 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700845 }
846 }
847 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800848}
849
850
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800851char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800852{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 // This is a recursive method, but thinking about it "at the current level"
854 // it is a pretty simple flat list:
855 // <foo/>
856 // <!-- comment -->
857 //
858 // With a special case:
859 // <foo>
860 // </foo>
861 // <!-- comment -->
862 //
863 // Where the closing element (/foo) *must* be the next thing after the opening
864 // element, and the names must match. BUT the tricky bit is that the closing
865 // element will be read by the child.
866 //
867 // 'endTag' is the end tag for this node, it is returned by a call to a child.
868 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800869
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 while( p && *p ) {
871 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800872
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300874 if ( node == 0 ) {
875 break;
876 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800877
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 StrPair endTag;
879 p = node->ParseDeep( p, &endTag );
880 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400881 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 if ( !_document->Error() ) {
883 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 break;
886 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400888 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500890 // We read the end tag. Return it to the parent.
891 if ( ele->ClosingType() == XMLElement::CLOSING ) {
892 if ( parentEnd ) {
893 ele->_value.TransferTo( parentEnd );
894 }
895 node->_memPool->SetTracked(); // created and then immediately deleted.
896 DeleteNode( node );
897 return p;
898 }
899
900 // Handle an end tag returned to this level.
901 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400902 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300903 if ( endTag.Empty() ) {
904 if ( ele->ClosingType() == XMLElement::OPEN ) {
905 mismatch = true;
906 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300908 else {
909 if ( ele->ClosingType() != XMLElement::OPEN ) {
910 mismatch = true;
911 }
912 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400913 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 }
915 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400916 if ( mismatch ) {
917 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500918 DeleteNode( node );
919 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400920 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 }
JayXondbfdd8f2014-12-12 20:07:14 -0500922 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 }
924 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800925}
926
Dmitry-Mee3225b12014-09-03 11:03:11 +0400927void XMLNode::DeleteNode( XMLNode* node )
928{
929 if ( node == 0 ) {
930 return;
931 }
932 MemPool* pool = node->_memPool;
933 node->~XMLNode();
934 pool->Free( node );
935}
936
Lee Thomason3cebdc42015-01-05 17:16:28 -0800937void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300938{
939 TIXMLASSERT( insertThis );
940 TIXMLASSERT( insertThis->_document == _document );
941
942 if ( insertThis->_parent )
943 insertThis->_parent->Unlink( insertThis );
944 else
945 insertThis->_memPool->SetTracked();
946}
947
Lee Thomason5492a1c2012-01-23 15:32:10 -0800948// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800949char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800950{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 const char* start = p;
952 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 return p;
958 }
959 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700960 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
961 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 flags |= StrPair::COLLAPSE_WHITESPACE;
963 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700964
Lee Thomason624d43f2012-10-12 10:58:48 -0700965 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( p && *p ) {
967 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300968 }
969 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300970 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 }
972 }
973 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800974}
975
976
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800977XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
983 text->SetCData( this->CData() );
984 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
988bool XMLText::ShallowEqual( const XMLNode* compare ) const
989{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400990 const XMLText* text = compare->ToText();
991 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800992}
993
994
Lee Thomason56bdd022012-02-09 18:16:58 -0800995bool XMLText::Accept( XMLVisitor* visitor ) const
996{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300997 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800999}
1000
1001
Lee Thomason3f57d272012-01-11 15:30:03 -08001002// --------- XMLComment ---------- //
1003
Lee Thomasone4422302012-01-20 17:59:50 -08001004XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001005{
1006}
1007
1008
Lee Thomasonce0763e2012-01-11 15:43:54 -08001009XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001010{
Lee Thomason3f57d272012-01-11 15:30:03 -08001011}
1012
1013
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001014char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 // Comment parses as text.
1017 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001018 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001020 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 }
1022 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001023}
1024
1025
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001026XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1027{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001029 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
1031 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1032 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001033}
1034
1035
1036bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1037{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001038 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001039 const XMLComment* comment = compare->ToComment();
1040 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001041}
1042
1043
Lee Thomason751da522012-02-10 08:50:51 -08001044bool XMLComment::Accept( XMLVisitor* visitor ) const
1045{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001046 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001048}
Lee Thomason56bdd022012-02-09 18:16:58 -08001049
1050
Lee Thomason50f97b22012-02-11 16:33:40 -08001051// --------- XMLDeclaration ---------- //
1052
1053XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1054{
1055}
1056
1057
1058XMLDeclaration::~XMLDeclaration()
1059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001061}
1062
1063
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001064char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 // Declaration parses as text.
1067 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001068 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 }
1072 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001073}
1074
1075
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001076XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001079 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 }
1081 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1082 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001083}
1084
1085
1086bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1087{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001088 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001089 const XMLDeclaration* declaration = compare->ToDeclaration();
1090 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001091}
1092
1093
1094
Lee Thomason50f97b22012-02-11 16:33:40 -08001095bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1096{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001097 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001099}
1100
1101// --------- XMLUnknown ---------- //
1102
1103XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1104{
1105}
1106
1107
1108XMLUnknown::~XMLUnknown()
1109{
1110}
1111
1112
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001113char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 // Unknown parses as text.
1116 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001117
Lee Thomason624d43f2012-10-12 10:58:48 -07001118 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001120 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 }
1122 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001123}
1124
1125
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001126XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 }
1131 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1132 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001133}
1134
1135
1136bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1137{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001138 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001139 const XMLUnknown* unknown = compare->ToUnknown();
1140 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001141}
1142
1143
Lee Thomason50f97b22012-02-11 16:33:40 -08001144bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1145{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001146 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001148}
1149
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001150// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001151
1152const char* XMLAttribute::Name() const
1153{
1154 return _name.GetStr();
1155}
1156
1157const char* XMLAttribute::Value() const
1158{
1159 return _value.GetStr();
1160}
1161
Lee Thomason6f381b72012-03-02 12:59:39 -08001162char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( !p || !*p ) {
1167 return 0;
1168 }
Lee Thomason22aead12012-01-23 13:29:35 -08001169
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 // Skip white space before =
1171 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001172 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 return 0;
1174 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001175
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 ++p; // move up to opening quote
1177 p = XMLUtil::SkipWhiteSpace( p );
1178 if ( *p != '\"' && *p != '\'' ) {
1179 return 0;
1180 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001181
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 char endTag[2] = { *p, 0 };
1183 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001184
Lee Thomason624d43f2012-10-12 10:58:48 -07001185 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001187}
1188
1189
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001190void XMLAttribute::SetName( const char* n )
1191{
Lee Thomason624d43f2012-10-12 10:58:48 -07001192 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001193}
1194
1195
Lee Thomason2fa81722012-11-09 12:37:46 -08001196XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( XMLUtil::ToInt( Value(), value )) {
1199 return XML_NO_ERROR;
1200 }
1201 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001202}
1203
1204
Lee Thomason2fa81722012-11-09 12:37:46 -08001205XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 if ( XMLUtil::ToUnsigned( Value(), value )) {
1208 return XML_NO_ERROR;
1209 }
1210 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211}
1212
1213
Lee Thomason2fa81722012-11-09 12:37:46 -08001214XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 if ( XMLUtil::ToBool( Value(), value )) {
1217 return XML_NO_ERROR;
1218 }
1219 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001220}
1221
1222
Lee Thomason2fa81722012-11-09 12:37:46 -08001223XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( XMLUtil::ToFloat( Value(), value )) {
1226 return XML_NO_ERROR;
1227 }
1228 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001229}
1230
1231
Lee Thomason2fa81722012-11-09 12:37:46 -08001232XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 if ( XMLUtil::ToDouble( Value(), value )) {
1235 return XML_NO_ERROR;
1236 }
1237 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001238}
1239
1240
1241void XMLAttribute::SetAttribute( const char* v )
1242{
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001244}
1245
1246
Lee Thomason1ff38e02012-02-14 18:18:16 -08001247void XMLAttribute::SetAttribute( int v )
1248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 char buf[BUF_SIZE];
1250 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001252}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001253
1254
1255void XMLAttribute::SetAttribute( unsigned v )
1256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 char buf[BUF_SIZE];
1258 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001260}
1261
1262
1263void XMLAttribute::SetAttribute( bool v )
1264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 char buf[BUF_SIZE];
1266 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001268}
1269
1270void XMLAttribute::SetAttribute( double v )
1271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 char buf[BUF_SIZE];
1273 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001275}
1276
1277void XMLAttribute::SetAttribute( float v )
1278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 char buf[BUF_SIZE];
1280 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001281 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001282}
1283
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001284
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001285// --------- XMLElement ---------- //
1286XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001287 _closingType( 0 ),
1288 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001289{
1290}
1291
1292
1293XMLElement::~XMLElement()
1294{
Lee Thomason624d43f2012-10-12 10:58:48 -07001295 while( _rootAttribute ) {
1296 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001297 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001300}
1301
1302
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001303const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1304{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001305 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1307 return a;
1308 }
1309 }
1310 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001311}
1312
1313
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001314const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 const XMLAttribute* a = FindAttribute( name );
1317 if ( !a ) {
1318 return 0;
1319 }
1320 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1321 return a->Value();
1322 }
1323 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001324}
1325
1326
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001327const char* XMLElement::GetText() const
1328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001330 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 }
1332 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001333}
1334
1335
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001336void XMLElement::SetText( const char* inText )
1337{
Uli Kusterer869bb592014-01-21 01:36:16 +01001338 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001339 FirstChild()->SetValue( inText );
1340 else {
1341 XMLText* theText = GetDocument()->NewText( inText );
1342 InsertFirstChild( theText );
1343 }
1344}
1345
Lee Thomason5bb2d802014-01-24 10:42:57 -08001346
1347void XMLElement::SetText( int v )
1348{
1349 char buf[BUF_SIZE];
1350 XMLUtil::ToStr( v, buf, BUF_SIZE );
1351 SetText( buf );
1352}
1353
1354
1355void XMLElement::SetText( unsigned v )
1356{
1357 char buf[BUF_SIZE];
1358 XMLUtil::ToStr( v, buf, BUF_SIZE );
1359 SetText( buf );
1360}
1361
1362
1363void XMLElement::SetText( bool v )
1364{
1365 char buf[BUF_SIZE];
1366 XMLUtil::ToStr( v, buf, BUF_SIZE );
1367 SetText( buf );
1368}
1369
1370
1371void XMLElement::SetText( float v )
1372{
1373 char buf[BUF_SIZE];
1374 XMLUtil::ToStr( v, buf, BUF_SIZE );
1375 SetText( buf );
1376}
1377
1378
1379void XMLElement::SetText( double v )
1380{
1381 char buf[BUF_SIZE];
1382 XMLUtil::ToStr( v, buf, BUF_SIZE );
1383 SetText( buf );
1384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001390 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001416 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 return XML_SUCCESS;
1419 }
1420 return XML_CAN_NOT_CONVERT_TEXT;
1421 }
1422 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
MortenMacFly4ee49f12013-01-14 20:03:14 +01001426XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001429 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001430 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 return XML_SUCCESS;
1432 }
1433 return XML_CAN_NOT_CONVERT_TEXT;
1434 }
1435 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001436}
1437
1438
MortenMacFly4ee49f12013-01-14 20:03:14 +01001439XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001442 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001443 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 return XML_SUCCESS;
1445 }
1446 return XML_CAN_NOT_CONVERT_TEXT;
1447 }
1448 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001449}
1450
1451
1452
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 XMLAttribute* last = 0;
1456 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1461 break;
1462 }
1463 }
1464 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001465 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1467 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
1471 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 }
1474 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001475 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 }
1477 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001478}
1479
1480
U-Stream\Leeae25a442012-02-17 17:48:16 -08001481void XMLElement::DeleteAttribute( const char* name )
1482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1486 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 }
1489 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001492 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 break;
1494 }
1495 prev = a;
1496 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001497}
1498
1499
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001500char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 const char* start = p;
1503 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001504
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 // Read the attributes.
1506 while( p ) {
1507 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001508 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 return 0;
1511 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001512
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001514 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001515 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1517 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001518 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001519
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001522 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 return 0;
1525 }
1526 // There is a minor bug here: if the attribute in the source xml
1527 // document is duplicated, it will not be detected and the
1528 // attribute will be doubly added. However, tracking the 'prevAttribute'
1529 // avoids re-scanning the attribute list. Preferring performance for
1530 // now, may reconsider in the future.
1531 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001532 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 }
1534 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 prevAttribute = attrib;
1538 }
1539 // end of the tag
1540 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 return p+2; // done; sealed element.
1543 }
1544 // end of the tag
1545 else if ( *p == '>' ) {
1546 ++p;
1547 break;
1548 }
1549 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 return 0;
1552 }
1553 }
1554 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001555}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001556
Dmitry-Mee3225b12014-09-03 11:03:11 +04001557void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1558{
1559 if ( attribute == 0 ) {
1560 return;
1561 }
1562 MemPool* pool = attribute->_memPool;
1563 attribute->~XMLAttribute();
1564 pool->Free( attribute );
1565}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001566
Lee Thomason67d61312012-01-24 16:01:51 -08001567//
1568// <ele></ele>
1569// <ele>foo<b>bar</b></ele>
1570//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001571char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 // Read the element name.
1574 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001575
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 // The closing element is the </element> form. It is
1577 // parsed just like a regular element then deleted from
1578 // the DOM.
1579 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001580 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 ++p;
1582 }
Lee Thomason67d61312012-01-24 16:01:51 -08001583
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 p = _value.ParseName( p );
1585 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 return 0;
1587 }
Lee Thomason67d61312012-01-24 16:01:51 -08001588
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 return p;
1592 }
Lee Thomason67d61312012-01-24 16:01:51 -08001593
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 p = XMLNode::ParseDeep( p, strPair );
1595 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001596}
1597
1598
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001599
1600XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 }
1605 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1606 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1607 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1608 }
1609 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001610}
1611
1612
1613bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1614{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001615 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 const XMLElement* other = compare->ToElement();
1617 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001618
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 const XMLAttribute* a=FirstAttribute();
1620 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001621
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 while ( a && b ) {
1623 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1624 return false;
1625 }
1626 a = a->Next();
1627 b = b->Next();
1628 }
1629 if ( a || b ) {
1630 // different count
1631 return false;
1632 }
1633 return true;
1634 }
1635 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001636}
1637
1638
Lee Thomason751da522012-02-10 08:50:51 -08001639bool XMLElement::Accept( XMLVisitor* visitor ) const
1640{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001641 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001642 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1644 if ( !node->Accept( visitor ) ) {
1645 break;
1646 }
1647 }
1648 }
1649 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001650}
Lee Thomason56bdd022012-02-09 18:16:58 -08001651
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001652
Lee Thomason3f57d272012-01-11 15:30:03 -08001653// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001654
1655// Warning: List must match 'enum XMLError'
1656const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1657 "XML_SUCCESS",
1658 "XML_NO_ATTRIBUTE",
1659 "XML_WRONG_ATTRIBUTE_TYPE",
1660 "XML_ERROR_FILE_NOT_FOUND",
1661 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1662 "XML_ERROR_FILE_READ_ERROR",
1663 "XML_ERROR_ELEMENT_MISMATCH",
1664 "XML_ERROR_PARSING_ELEMENT",
1665 "XML_ERROR_PARSING_ATTRIBUTE",
1666 "XML_ERROR_IDENTIFYING_TAG",
1667 "XML_ERROR_PARSING_TEXT",
1668 "XML_ERROR_PARSING_CDATA",
1669 "XML_ERROR_PARSING_COMMENT",
1670 "XML_ERROR_PARSING_DECLARATION",
1671 "XML_ERROR_PARSING_UNKNOWN",
1672 "XML_ERROR_EMPTY_DOCUMENT",
1673 "XML_ERROR_MISMATCHED_ELEMENT",
1674 "XML_ERROR_PARSING",
1675 "XML_CAN_NOT_CONVERT_TEXT",
1676 "XML_NO_TEXT_NODE"
1677};
1678
1679
Lee Thomason624d43f2012-10-12 10:58:48 -07001680XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001682 _writeBOM( false ),
1683 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001684 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 _whitespace( whitespace ),
1686 _errorStr1( 0 ),
1687 _errorStr2( 0 ),
1688 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001689{
Lee Thomason624d43f2012-10-12 10:58:48 -07001690 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001691}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001692
1693
Lee Thomason3f57d272012-01-11 15:30:03 -08001694XMLDocument::~XMLDocument()
1695{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001696 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001697}
1698
1699
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001700void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001701{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001702 DeleteChildren();
1703
Dmitry-Meab37df82014-11-28 12:08:36 +03001704#ifdef DEBUG
1705 const bool hadError = Error();
1706#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 _errorID = XML_NO_ERROR;
1708 _errorStr1 = 0;
1709 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001710
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 delete [] _charBuffer;
1712 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001713
1714#if 0
1715 _textPool.Trace( "text" );
1716 _elementPool.Trace( "element" );
1717 _commentPool.Trace( "comment" );
1718 _attributePool.Trace( "attribute" );
1719#endif
1720
1721#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001722 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001723 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1724 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1725 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1726 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1727 }
1728#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001729}
1730
Lee Thomason3f57d272012-01-11 15:30:03 -08001731
Lee Thomason2c85a712012-01-31 08:24:24 -08001732XMLElement* XMLDocument::NewElement( const char* name )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1736 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 ele->SetName( name );
1738 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001739}
1740
1741
Lee Thomason1ff38e02012-02-14 18:18:16 -08001742XMLComment* XMLDocument::NewComment( const char* str )
1743{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001744 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1746 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 comment->SetValue( str );
1748 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001749}
1750
1751
1752XMLText* XMLDocument::NewText( const char* str )
1753{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001754 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1756 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 text->SetValue( str );
1758 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001759}
1760
1761
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001762XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1763{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001764 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1766 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1768 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001769}
1770
1771
1772XMLUnknown* XMLDocument::NewUnknown( const char* str )
1773{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001774 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1776 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 unk->SetValue( str );
1778 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001779}
1780
Dmitry-Me01578db2014-08-19 10:18:48 +04001781static FILE* callfopen( const char* filepath, const char* mode )
1782{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001783 TIXMLASSERT( filepath );
1784 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001785#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1786 FILE* fp = 0;
1787 errno_t err = fopen_s( &fp, filepath, mode );
1788 if ( err ) {
1789 return 0;
1790 }
1791#else
1792 FILE* fp = fopen( filepath, mode );
1793#endif
1794 return fp;
1795}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001796
1797void XMLDocument::DeleteNode( XMLNode* node ) {
1798 TIXMLASSERT( node );
1799 TIXMLASSERT(node->_document == this );
1800 if (node->_parent) {
1801 node->_parent->DeleteChild( node );
1802 }
1803 else {
1804 // Isn't in the tree.
1805 // Use the parent delete.
1806 // Also, we need to mark it tracked: we 'know'
1807 // it was never used.
1808 node->_memPool->SetTracked();
1809 // Call the static XMLNode version:
1810 XMLNode::DeleteNode(node);
1811 }
1812}
1813
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001814
Lee Thomason2fa81722012-11-09 12:37:46 -08001815XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001816{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001817 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001818 FILE* fp = callfopen( filename, "rb" );
1819 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
1823 LoadFile( fp );
1824 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826}
1827
1828
Lee Thomason2fa81722012-11-09 12:37:46 -08001829XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001830{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001831 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001833 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001834 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001835 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1836 return _errorID;
1837 }
1838
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001840 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001842 if ( filelength == -1L ) {
1843 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1844 return _errorID;
1845 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001846
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001847 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001849 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001852
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 _charBuffer = new char[size+1];
1854 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 if ( read != size ) {
1856 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001859
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001861
Dmitry-Me97476b72015-01-01 16:15:57 +03001862 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001864}
1865
1866
Lee Thomason2fa81722012-11-09 12:37:46 -08001867XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001868{
Dmitry-Me01578db2014-08-19 10:18:48 +04001869 FILE* fp = callfopen( filename, "w" );
1870 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
1874 SaveFile(fp, compact);
1875 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001877}
1878
1879
Lee Thomason2fa81722012-11-09 12:37:46 -08001880XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001881{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 XMLPrinter stream( fp, compact );
1883 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001885}
1886
Lee Thomason1ff38e02012-02-14 18:18:16 -08001887
Lee Thomason2fa81722012-11-09 12:37:46 -08001888XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001889{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001890 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001891
Lee Thomason82d32002014-02-21 22:47:18 -08001892 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 }
1896 if ( len == (size_t)(-1) ) {
1897 len = strlen( p );
1898 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 _charBuffer = new char[ len+1 ];
1900 memcpy( _charBuffer, p, len );
1901 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001902
Dmitry-Me97476b72015-01-01 16:15:57 +03001903 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001904 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001905 // clean up now essentially dangling memory.
1906 // and the parse fail can put objects in the
1907 // pools that are dead and inaccessible.
1908 DeleteChildren();
1909 _elementPool.Clear();
1910 _attributePool.Clear();
1911 _textPool.Clear();
1912 _commentPool.Clear();
1913 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001915}
1916
1917
PKEuS1c5f99e2013-07-06 11:28:39 +02001918void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 XMLPrinter stdStreamer( stdout );
1921 if ( !streamer ) {
1922 streamer = &stdStreamer;
1923 }
1924 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001925}
1926
1927
Lee Thomason2fa81722012-11-09 12:37:46 -08001928void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001929{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001930 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001931 _errorID = error;
1932 _errorStr1 = str1;
1933 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001934}
1935
Lee Thomason331596e2014-09-11 14:56:43 -07001936const char* XMLDocument::ErrorName() const
1937{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001938 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001939 return _errorNames[_errorID];
1940}
Lee Thomason5cae8972012-01-24 18:03:07 -08001941
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001942void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001944 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 static const int LEN = 20;
1946 char buf1[LEN] = { 0 };
1947 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001948
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 if ( _errorStr1 ) {
1950 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 if ( _errorStr2 ) {
1953 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955
Lee Thomason331596e2014-09-11 14:56:43 -07001956 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1957 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001959}
1960
Dmitry-Me97476b72015-01-01 16:15:57 +03001961void XMLDocument::Parse()
1962{
1963 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1964 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001965 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001966 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001967 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001968 if ( !*p ) {
1969 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1970 return;
1971 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001972 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001973}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001974
PKEuS1bfb9542013-08-04 13:51:17 +02001975XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _elementJustOpened( false ),
1977 _firstElement( true ),
1978 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001979 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001980 _textDepth( -1 ),
1981 _processEntities( true ),
1982 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001984 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 _entityFlag[i] = false;
1986 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 }
1988 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001989 const char entityValue = entities[i].value;
1990 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1991 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001993 _restrictedEntityFlag[(unsigned char)'&'] = true;
1994 _restrictedEntityFlag[(unsigned char)'<'] = true;
1995 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001996 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001997}
1998
1999
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002000void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002001{
2002 va_list va;
2003 va_start( va, format );
2004
Lee Thomason624d43f2012-10-12 10:58:48 -07002005 if ( _fp ) {
2006 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 }
2008 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002009#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002010 #if defined(WINCE)
2011 int len = 512;
2012 do {
2013 len = len*2;
2014 char* str = new char[len]();
2015 len = _vsnprintf(str, len, format, va);
2016 delete[] str;
2017 }while (len < 0);
2018 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002019 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002020 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021#else
2022 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002023#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 // Close out and re-start the va-args
2025 va_end( va );
2026 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002027 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002028 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2029#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002030 #if defined(WINCE)
2031 _vsnprintf( p, len+1, format, va );
2032 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002033 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002034 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002035#else
2036 vsnprintf( p, len+1, format, va );
2037#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002039 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 for( int i=0; i<depth; ++i ) {
2046 Print( " " );
2047 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002048}
2049
2050
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002051void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002052{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 // Look for runs of bytes between entities to print.
2054 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002055
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002057 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 while ( *q ) {
2059 // Remember, char is sometimes signed. (How many times has that bitten me?)
2060 if ( *q > 0 && *q < ENTITY_RANGE ) {
2061 // Check for entities. If one is found, flush
2062 // the stream up until the entity, write the
2063 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002064 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 while ( p < q ) {
2066 Print( "%c", *p );
2067 ++p;
2068 }
2069 for( int i=0; i<NUM_ENTITIES; ++i ) {
2070 if ( entities[i].value == *q ) {
2071 Print( "&%s;", entities[i].pattern );
2072 break;
2073 }
2074 }
2075 ++p;
2076 }
2077 }
2078 ++q;
2079 }
2080 }
2081 // Flush the remaining string. This will be the entire
2082 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 Print( "%s", p );
2085 }
Lee Thomason857b8682012-01-25 17:50:25 -08002086}
2087
U-Stream\Leeae25a442012-02-17 17:48:16 -08002088
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002089void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002092 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 -07002093 Print( "%s", bom );
2094 }
2095 if ( writeDec ) {
2096 PushDeclaration( "xml version=\"1.0\"" );
2097 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002098}
2099
2100
Uli Kusterer593a33d2014-02-01 12:48:51 +01002101void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002102{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002103 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002104 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002105
Uli Kusterer593a33d2014-02-01 12:48:51 +01002106 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002108 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002109 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002112
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 _elementJustOpened = true;
2115 _firstElement = false;
2116 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002117}
2118
2119
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002120void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002121{
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 Print( " %s=\"", name );
2124 PrintString( value, false );
2125 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002126}
2127
2128
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002129void XMLPrinter::PushAttribute( const char* name, int v )
2130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 char buf[BUF_SIZE];
2132 XMLUtil::ToStr( v, buf, BUF_SIZE );
2133 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002134}
2135
2136
2137void XMLPrinter::PushAttribute( const char* name, unsigned 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, bool 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, double 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
Uli Kustererca412e82014-02-01 13:35:05 +01002161void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002162{
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 --_depth;
2164 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002165
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( "/>" );
2168 }
2169 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002170 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 }
2174 Print( "</%s>", name );
2175 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002176
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 if ( _textDepth == _depth ) {
2178 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
Uli Kustererca412e82014-02-01 13:35:05 +01002180 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 Print( "\n" );
2182 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002184}
2185
2186
Dmitry-Mea092bc12014-12-23 17:57:05 +03002187void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002188{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002189 if ( !_elementJustOpened ) {
2190 return;
2191 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002192 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002194}
2195
2196
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002197void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002198{
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002200
Dmitry-Mea092bc12014-12-23 17:57:05 +03002201 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 if ( cdata ) {
2203 Print( "<![CDATA[" );
2204 Print( "%s", text );
2205 Print( "]]>" );
2206 }
2207 else {
2208 PrintString( text, true );
2209 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002210}
2211
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002212void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 char buf[BUF_SIZE];
2215 XMLUtil::ToStr( value, buf, BUF_SIZE );
2216 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002217}
2218
2219
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002220void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 char buf[BUF_SIZE];
2223 XMLUtil::ToStr( value, buf, BUF_SIZE );
2224 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002225}
2226
2227
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002228void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 char buf[BUF_SIZE];
2231 XMLUtil::ToStr( value, buf, BUF_SIZE );
2232 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002233}
2234
2235
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002236void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 char buf[BUF_SIZE];
2239 XMLUtil::ToStr( value, buf, BUF_SIZE );
2240 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002241}
2242
2243
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002244void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 char buf[BUF_SIZE];
2247 XMLUtil::ToStr( value, buf, BUF_SIZE );
2248 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002249}
2250
Lee Thomason5cae8972012-01-24 18:03:07 -08002251
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002252void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002253{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002254 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002261}
Lee Thomason751da522012-02-10 08:50:51 -08002262
2263
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002264void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002265{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002266 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002267 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002273}
2274
2275
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002276void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002277{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002278 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002279 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002282 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002289{
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 if ( doc.HasBOM() ) {
2292 PushHeader( true, false );
2293 }
2294 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002295}
2296
2297
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002298bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002299{
Ant Mitchell7e744772015-03-24 14:33:28 +00002300 const XMLElement* parentElem = NULL;
2301 if ( element.Parent() )
2302 {
2303 parentElem = element.Parent()->ToElement();
2304 }
2305 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002306 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 while ( attribute ) {
2308 PushAttribute( attribute->Name(), attribute->Value() );
2309 attribute = attribute->Next();
2310 }
2311 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002312}
2313
2314
Uli Kustererca412e82014-02-01 13:35:05 +01002315bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002316{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002317 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002318 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002319}
2320
2321
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002322bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 PushText( text.Value(), text.CData() );
2325 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002326}
2327
2328
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002329bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 PushComment( comment.Value() );
2332 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002333}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002334
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002335bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 PushDeclaration( declaration.Value() );
2338 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002339}
2340
2341
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002342bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002344 PushUnknown( unknown.Value() );
2345 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002346}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002347
Lee Thomason685b8952012-11-12 13:00:06 -08002348} // namespace tinyxml2
2349