blob: ebf28651b09c33de8f159fb96dac34ad02022355 [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{
Ant Mitchell189198f2015-03-24 16:20:36 +00001882 // Clear any error from the last save, otherwise it will get reported
1883 // for *this* call.
1884 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 XMLPrinter stream( fp, compact );
1886 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001888}
1889
Lee Thomason1ff38e02012-02-14 18:18:16 -08001890
Lee Thomason2fa81722012-11-09 12:37:46 -08001891XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001892{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001893 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001894
Lee Thomason82d32002014-02-21 22:47:18 -08001895 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 }
1899 if ( len == (size_t)(-1) ) {
1900 len = strlen( p );
1901 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 _charBuffer = new char[ len+1 ];
1903 memcpy( _charBuffer, p, len );
1904 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001905
Dmitry-Me97476b72015-01-01 16:15:57 +03001906 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001907 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001908 // clean up now essentially dangling memory.
1909 // and the parse fail can put objects in the
1910 // pools that are dead and inaccessible.
1911 DeleteChildren();
1912 _elementPool.Clear();
1913 _attributePool.Clear();
1914 _textPool.Clear();
1915 _commentPool.Clear();
1916 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001918}
1919
1920
PKEuS1c5f99e2013-07-06 11:28:39 +02001921void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001922{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 XMLPrinter stdStreamer( stdout );
1924 if ( !streamer ) {
1925 streamer = &stdStreamer;
1926 }
1927 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001928}
1929
1930
Lee Thomason2fa81722012-11-09 12:37:46 -08001931void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001932{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001933 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 _errorID = error;
1935 _errorStr1 = str1;
1936 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001937}
1938
Lee Thomason331596e2014-09-11 14:56:43 -07001939const char* XMLDocument::ErrorName() const
1940{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001941 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001942 return _errorNames[_errorID];
1943}
Lee Thomason5cae8972012-01-24 18:03:07 -08001944
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001945void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001946{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001947 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 static const int LEN = 20;
1949 char buf1[LEN] = { 0 };
1950 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001951
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 if ( _errorStr1 ) {
1953 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 if ( _errorStr2 ) {
1956 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001958
Lee Thomason331596e2014-09-11 14:56:43 -07001959 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1960 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001962}
1963
Dmitry-Me97476b72015-01-01 16:15:57 +03001964void XMLDocument::Parse()
1965{
1966 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1967 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001968 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001969 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001970 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001971 if ( !*p ) {
1972 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1973 return;
1974 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001975 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001976}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977
PKEuS1bfb9542013-08-04 13:51:17 +02001978XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 _elementJustOpened( false ),
1980 _firstElement( true ),
1981 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001982 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001983 _textDepth( -1 ),
1984 _processEntities( true ),
1985 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 _entityFlag[i] = false;
1989 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
1991 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001992 const char entityValue = entities[i].value;
1993 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1994 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001996 _restrictedEntityFlag[(unsigned char)'&'] = true;
1997 _restrictedEntityFlag[(unsigned char)'<'] = true;
1998 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002000}
2001
2002
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002003void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002004{
2005 va_list va;
2006 va_start( va, format );
2007
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 if ( _fp ) {
2009 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 }
2011 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002012#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002013 #if defined(WINCE)
2014 int len = 512;
2015 do {
2016 len = len*2;
2017 char* str = new char[len]();
2018 len = _vsnprintf(str, len, format, va);
2019 delete[] str;
2020 }while (len < 0);
2021 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002022 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002023 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024#else
2025 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002026#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 // Close out and re-start the va-args
2028 va_end( va );
2029 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002030 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002031 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2032#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002033 #if defined(WINCE)
2034 _vsnprintf( p, len+1, format, va );
2035 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002036 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002037 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002038#else
2039 vsnprintf( p, len+1, format, va );
2040#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002042 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002043}
2044
2045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002046void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 for( int i=0; i<depth; ++i ) {
2049 Print( " " );
2050 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002051}
2052
2053
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002054void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 // Look for runs of bytes between entities to print.
2057 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002058
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002060 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 while ( *q ) {
2062 // Remember, char is sometimes signed. (How many times has that bitten me?)
2063 if ( *q > 0 && *q < ENTITY_RANGE ) {
2064 // Check for entities. If one is found, flush
2065 // the stream up until the entity, write the
2066 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002067 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002069 const size_t delta = q - p;
2070 // %.*s accepts type int as "precision"
2071 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2072 Print( "%.*s", toPrint, p );
2073 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 }
2075 for( int i=0; i<NUM_ENTITIES; ++i ) {
2076 if ( entities[i].value == *q ) {
2077 Print( "&%s;", entities[i].pattern );
2078 break;
2079 }
2080 }
2081 ++p;
2082 }
2083 }
2084 ++q;
2085 }
2086 }
2087 // Flush the remaining string. This will be the entire
2088 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 Print( "%s", p );
2091 }
Lee Thomason857b8682012-01-25 17:50:25 -08002092}
2093
U-Stream\Leeae25a442012-02-17 17:48:16 -08002094
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002095void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002098 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 -07002099 Print( "%s", bom );
2100 }
2101 if ( writeDec ) {
2102 PushDeclaration( "xml version=\"1.0\"" );
2103 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002104}
2105
2106
Uli Kusterer593a33d2014-02-01 12:48:51 +01002107void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002108{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002109 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002111
Uli Kusterer593a33d2014-02-01 12:48:51 +01002112 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002114 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002115 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002118
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 _elementJustOpened = true;
2121 _firstElement = false;
2122 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002123}
2124
2125
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002126void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002127{
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 Print( " %s=\"", name );
2130 PrintString( value, false );
2131 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002132}
2133
2134
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002135void XMLPrinter::PushAttribute( const char* name, int v )
2136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 char buf[BUF_SIZE];
2138 XMLUtil::ToStr( v, buf, BUF_SIZE );
2139 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002140}
2141
2142
2143void XMLPrinter::PushAttribute( const char* name, unsigned v )
2144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 char buf[BUF_SIZE];
2146 XMLUtil::ToStr( v, buf, BUF_SIZE );
2147 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002148}
2149
2150
2151void XMLPrinter::PushAttribute( const char* name, bool v )
2152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 char buf[BUF_SIZE];
2154 XMLUtil::ToStr( v, buf, BUF_SIZE );
2155 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002156}
2157
2158
2159void XMLPrinter::PushAttribute( const char* name, double v )
2160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 char buf[BUF_SIZE];
2162 XMLUtil::ToStr( v, buf, BUF_SIZE );
2163 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002164}
2165
2166
Uli Kustererca412e82014-02-01 13:35:05 +01002167void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002168{
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 --_depth;
2170 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002171
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 Print( "/>" );
2174 }
2175 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002176 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
2180 Print( "</%s>", name );
2181 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002182
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 if ( _textDepth == _depth ) {
2184 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 }
Uli Kustererca412e82014-02-01 13:35:05 +01002186 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 Print( "\n" );
2188 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002189 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002190}
2191
2192
Dmitry-Mea092bc12014-12-23 17:57:05 +03002193void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002194{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002195 if ( !_elementJustOpened ) {
2196 return;
2197 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002198 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002200}
2201
2202
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002203void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002204{
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002206
Dmitry-Mea092bc12014-12-23 17:57:05 +03002207 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 if ( cdata ) {
2209 Print( "<![CDATA[" );
2210 Print( "%s", text );
2211 Print( "]]>" );
2212 }
2213 else {
2214 PrintString( text, true );
2215 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002216}
2217
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002218void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 char buf[BUF_SIZE];
2221 XMLUtil::ToStr( value, buf, BUF_SIZE );
2222 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002223}
2224
2225
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002226void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 char buf[BUF_SIZE];
2229 XMLUtil::ToStr( value, buf, BUF_SIZE );
2230 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002231}
2232
2233
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002234void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 char buf[BUF_SIZE];
2237 XMLUtil::ToStr( value, buf, BUF_SIZE );
2238 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002239}
2240
2241
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002242void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 char buf[BUF_SIZE];
2245 XMLUtil::ToStr( value, buf, BUF_SIZE );
2246 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002247}
2248
2249
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002250void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 char buf[BUF_SIZE];
2253 XMLUtil::ToStr( value, buf, BUF_SIZE );
2254 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002255}
2256
Lee Thomason5cae8972012-01-24 18:03:07 -08002257
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002258void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002259{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002260 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002267}
Lee Thomason751da522012-02-10 08:50:51 -08002268
2269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002271{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002272 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002273 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002275 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002279}
2280
2281
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002282void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002283{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002284 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002291}
2292
2293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002295{
Lee Thomason624d43f2012-10-12 10:58:48 -07002296 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 if ( doc.HasBOM() ) {
2298 PushHeader( true, false );
2299 }
2300 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002301}
2302
2303
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002304bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002305{
Lee Thomason3ccb1ce2015-03-24 11:17:44 -07002306 const XMLElement* parentElem = NULL;
2307 if ( element.Parent() ) {
2308 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002309 }
Lee Thomason3ccb1ce2015-03-24 11:17:44 -07002310 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002311 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 while ( attribute ) {
2313 PushAttribute( attribute->Name(), attribute->Value() );
2314 attribute = attribute->Next();
2315 }
2316 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002317}
2318
2319
Uli Kustererca412e82014-02-01 13:35:05 +01002320bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002321{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002322 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002324}
2325
2326
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002327bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 PushText( text.Value(), text.CData() );
2330 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002331}
2332
2333
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002334bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 PushComment( comment.Value() );
2337 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002338}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002339
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002340bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 PushDeclaration( declaration.Value() );
2343 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002344}
2345
2346
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002347bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 PushUnknown( unknown.Value() );
2350 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002351}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002352
Lee Thomason685b8952012-11-12 13:00:06 -08002353} // namespace tinyxml2
2354