blob: 45a3e6d0d2033f7a161624ccb2c722bfc8aba529 [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-Mebab9b6d2015-03-14 16:41:46 +0300400 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
Lee Thomason7265b762015-03-15 16:11:47 -0700401 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300402 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';
430 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
431 const unsigned int digitScaled = mult * digit;
432 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
433 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 }
435 else {
436 return 0;
437 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300438 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 mult *= 10;
440 --q;
441 }
442 }
443 // convert the UCS to UTF-8
444 ConvertUTF32ToUTF8( ucs, value, length );
445 return p + delta + 1;
446 }
447 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800449
450
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700451void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700454}
455
456
457void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700460}
461
462
463void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800468/*
469 ToStr() of a number is a very tricky topic.
470 https://github.com/leethomason/tinyxml2/issues/106
471*/
Lee Thomason21be8822012-07-15 17:27:22 -0700472void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
473{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800474 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700475}
476
477
478void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
479{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800480 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700481}
482
483
484bool XMLUtil::ToInt( const char* str, int* value )
485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
493{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
495 return true;
496 }
497 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700498}
499
500bool XMLUtil::ToBool( const char* str, bool* value )
501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 int ival = 0;
503 if ( ToInt( str, &ival )) {
504 *value = (ival==0) ? false : true;
505 return true;
506 }
507 if ( StringEqual( str, "true" ) ) {
508 *value = true;
509 return true;
510 }
511 else if ( StringEqual( str, "false" ) ) {
512 *value = false;
513 return true;
514 }
515 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700516}
517
518
519bool XMLUtil::ToFloat( const char* str, float* value )
520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
522 return true;
523 }
524 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700525}
526
527bool XMLUtil::ToDouble( const char* str, double* value )
528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
530 return true;
531 }
532 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700533}
534
535
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700536char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800537{
Dmitry-Me02384662015-03-03 16:02:13 +0300538 TIXMLASSERT( node );
539 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400540 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300542 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300543 *node = 0;
544 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 return p;
546 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800547
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800549 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 static const char* xmlHeader = { "<?" };
551 static const char* commentHeader = { "<!--" };
552 static const char* dtdHeader = { "<!" };
553 static const char* cdataHeader = { "<![CDATA[" };
554 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800555
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 static const int xmlHeaderLen = 2;
557 static const int commentHeaderLen = 4;
558 static const int dtdHeaderLen = 2;
559 static const int cdataHeaderLen = 9;
560 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
563 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400564 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300566 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
568 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 p += xmlHeaderLen;
570 }
571 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300572 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700573 returnNode = new (_commentPool.Alloc()) XMLComment( this );
574 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 p += commentHeaderLen;
576 }
577 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300578 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700579 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 p += cdataHeaderLen;
583 text->SetCData( true );
584 }
585 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300586 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700587 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
588 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 p += dtdHeaderLen;
590 }
591 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300592 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 returnNode = new (_elementPool.Alloc()) XMLElement( this );
594 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 p += elementHeaderLen;
596 }
597 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300598 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700599 returnNode = new (_textPool.Alloc()) XMLText( this );
600 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 p = start; // Back it up, all the text counts.
602 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800603
Dmitry-Me02384662015-03-03 16:02:13 +0300604 TIXMLASSERT( returnNode );
605 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 *node = returnNode;
607 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800608}
609
610
Lee Thomason751da522012-02-10 08:50:51 -0800611bool XMLDocument::Accept( XMLVisitor* visitor ) const
612{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300613 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 if ( visitor->VisitEnter( *this ) ) {
615 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
616 if ( !node->Accept( visitor ) ) {
617 break;
618 }
619 }
620 }
621 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800622}
Lee Thomason56bdd022012-02-09 18:16:58 -0800623
624
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800625// --------- XMLNode ----------- //
626
627XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 _document( doc ),
629 _parent( 0 ),
630 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200631 _prev( 0 ), _next( 0 ),
632 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800633{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634}
635
636
637XMLNode::~XMLNode()
638{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 if ( _parent ) {
641 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800643}
644
Michael Daumling21626882013-10-22 17:03:37 +0200645const char* XMLNode::Value() const
646{
647 return _value.GetStr();
648}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800649
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800650void XMLNode::SetValue( const char* str, bool staticMem )
651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
655 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800658}
659
660
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800661void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800662{
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300664 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700667
Dmitry-Mee3225b12014-09-03 11:03:11 +0400668 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800671}
672
673
674void XMLNode::Unlink( XMLNode* child )
675{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300676 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300677 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( child == _firstChild ) {
679 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 if ( child == _lastChild ) {
682 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 }
Lee Thomasond923c672012-01-23 08:44:25 -0800684
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 if ( child->_prev ) {
686 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( child->_next ) {
689 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700691 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692}
693
694
U-Stream\Leeae25a442012-02-17 17:48:16 -0800695void XMLNode::DeleteChild( XMLNode* node )
696{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300697 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300698 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400700 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800701}
702
703
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800704XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
705{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300706 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300707 if ( addThis->_document != _document ) {
708 TIXMLASSERT( false );
709 return 0;
710 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800711 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 if ( _lastChild ) {
714 TIXMLASSERT( _firstChild );
715 TIXMLASSERT( _lastChild->_next == 0 );
716 _lastChild->_next = addThis;
717 addThis->_prev = _lastChild;
718 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800719
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 }
722 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 TIXMLASSERT( _firstChild == 0 );
724 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 addThis->_prev = 0;
727 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700730 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800731}
732
733
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
735{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300736 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300737 if ( addThis->_document != _document ) {
738 TIXMLASSERT( false );
739 return 0;
740 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800741 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700742
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 if ( _firstChild ) {
744 TIXMLASSERT( _lastChild );
745 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 _firstChild->_prev = addThis;
748 addThis->_next = _firstChild;
749 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 }
753 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 TIXMLASSERT( _lastChild == 0 );
755 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800756
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 addThis->_prev = 0;
758 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400761 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800762}
763
764
765XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
766{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300767 TIXMLASSERT( addThis );
768 if ( addThis->_document != _document ) {
769 TIXMLASSERT( false );
770 return 0;
771 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700772
Dmitry-Meabb2d042014-12-09 12:59:31 +0300773 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700774
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 return 0;
778 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800779
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 // The last node or the only node.
782 return InsertEndChild( addThis );
783 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800784 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 addThis->_prev = afterThis;
786 addThis->_next = afterThis->_next;
787 afterThis->_next->_prev = addThis;
788 afterThis->_next = addThis;
789 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800791}
792
793
794
795
Lee Thomason56bdd022012-02-09 18:16:58 -0800796const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800797{
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 XMLElement* element = node->ToElement();
800 if ( element ) {
801 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
802 return element;
803 }
804 }
805 }
806 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800807}
808
809
Lee Thomason56bdd022012-02-09 18:16:58 -0800810const XMLElement* XMLNode::LastChildElement( const char* value ) const
811{
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 XMLElement* element = node->ToElement();
814 if ( element ) {
815 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
816 return element;
817 }
818 }
819 }
820 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800821}
822
823
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800824const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
825{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400826 for( XMLNode* node=this->_next; node; node = node->_next ) {
827 const XMLElement* element = node->ToElement();
828 if ( element
829 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
830 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
832 }
833 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800834}
835
836
837const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
838{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400839 for( XMLNode* node=_prev; node; node = node->_prev ) {
840 const XMLElement* element = node->ToElement();
841 if ( element
842 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
843 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 }
845 }
846 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800847}
848
849
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800850char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800851{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 // This is a recursive method, but thinking about it "at the current level"
853 // it is a pretty simple flat list:
854 // <foo/>
855 // <!-- comment -->
856 //
857 // With a special case:
858 // <foo>
859 // </foo>
860 // <!-- comment -->
861 //
862 // Where the closing element (/foo) *must* be the next thing after the opening
863 // element, and the names must match. BUT the tricky bit is that the closing
864 // element will be read by the child.
865 //
866 // 'endTag' is the end tag for this node, it is returned by a call to a child.
867 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800868
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 while( p && *p ) {
870 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300873 if ( node == 0 ) {
874 break;
875 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800876
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 StrPair endTag;
878 p = node->ParseDeep( p, &endTag );
879 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400880 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( !_document->Error() ) {
882 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 break;
885 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800886
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400887 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500889 // We read the end tag. Return it to the parent.
890 if ( ele->ClosingType() == XMLElement::CLOSING ) {
891 if ( parentEnd ) {
892 ele->_value.TransferTo( parentEnd );
893 }
894 node->_memPool->SetTracked(); // created and then immediately deleted.
895 DeleteNode( node );
896 return p;
897 }
898
899 // Handle an end tag returned to this level.
900 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400901 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300902 if ( endTag.Empty() ) {
903 if ( ele->ClosingType() == XMLElement::OPEN ) {
904 mismatch = true;
905 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300907 else {
908 if ( ele->ClosingType() != XMLElement::OPEN ) {
909 mismatch = true;
910 }
911 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400912 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 }
914 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400915 if ( mismatch ) {
916 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500917 DeleteNode( node );
918 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400919 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
JayXondbfdd8f2014-12-12 20:07:14 -0500921 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 }
923 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800924}
925
Dmitry-Mee3225b12014-09-03 11:03:11 +0400926void XMLNode::DeleteNode( XMLNode* node )
927{
928 if ( node == 0 ) {
929 return;
930 }
931 MemPool* pool = node->_memPool;
932 node->~XMLNode();
933 pool->Free( node );
934}
935
Lee Thomason3cebdc42015-01-05 17:16:28 -0800936void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300937{
938 TIXMLASSERT( insertThis );
939 TIXMLASSERT( insertThis->_document == _document );
940
941 if ( insertThis->_parent )
942 insertThis->_parent->Unlink( insertThis );
943 else
944 insertThis->_memPool->SetTracked();
945}
946
Lee Thomason5492a1c2012-01-23 15:32:10 -0800947// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800948char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 const char* start = p;
951 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700952 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 return p;
957 }
958 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
960 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 flags |= StrPair::COLLAPSE_WHITESPACE;
962 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700963
Lee Thomason624d43f2012-10-12 10:58:48 -0700964 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 if ( p && *p ) {
966 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300967 }
968 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300969 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 }
972 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800973}
974
975
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
977{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
982 text->SetCData( this->CData() );
983 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984}
985
986
987bool XMLText::ShallowEqual( const XMLNode* compare ) const
988{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400989 const XMLText* text = compare->ToText();
990 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800991}
992
993
Lee Thomason56bdd022012-02-09 18:16:58 -0800994bool XMLText::Accept( XMLVisitor* visitor ) const
995{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300996 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800998}
999
1000
Lee Thomason3f57d272012-01-11 15:30:03 -08001001// --------- XMLComment ---------- //
1002
Lee Thomasone4422302012-01-20 17:59:50 -08001003XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001004{
1005}
1006
1007
Lee Thomasonce0763e2012-01-11 15:43:54 -08001008XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001009{
Lee Thomason3f57d272012-01-11 15:30:03 -08001010}
1011
1012
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001013char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001014{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 // Comment parses as text.
1016 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001019 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 }
1021 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001022}
1023
1024
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001025XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001028 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 }
1030 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1031 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001032}
1033
1034
1035bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1036{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001037 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001038 const XMLComment* comment = compare->ToComment();
1039 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001040}
1041
1042
Lee Thomason751da522012-02-10 08:50:51 -08001043bool XMLComment::Accept( XMLVisitor* visitor ) const
1044{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001045 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001047}
Lee Thomason56bdd022012-02-09 18:16:58 -08001048
1049
Lee Thomason50f97b22012-02-11 16:33:40 -08001050// --------- XMLDeclaration ---------- //
1051
1052XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1053{
1054}
1055
1056
1057XMLDeclaration::~XMLDeclaration()
1058{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001060}
1061
1062
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001063char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001064{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 // Declaration parses as text.
1066 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001067 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001069 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
1071 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001072}
1073
1074
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001075XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001078 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 }
1080 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1081 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001082}
1083
1084
1085bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1086{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001087 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001088 const XMLDeclaration* declaration = compare->ToDeclaration();
1089 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001090}
1091
1092
1093
Lee Thomason50f97b22012-02-11 16:33:40 -08001094bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1095{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001096 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001098}
1099
1100// --------- XMLUnknown ---------- //
1101
1102XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1103{
1104}
1105
1106
1107XMLUnknown::~XMLUnknown()
1108{
1109}
1110
1111
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001112char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 // Unknown parses as text.
1115 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001116
Lee Thomason624d43f2012-10-12 10:58:48 -07001117 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001119 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001122}
1123
1124
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001125XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 }
1130 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1131 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001132}
1133
1134
1135bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1136{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001137 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001138 const XMLUnknown* unknown = compare->ToUnknown();
1139 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001140}
1141
1142
Lee Thomason50f97b22012-02-11 16:33:40 -08001143bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1144{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001145 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001147}
1148
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001149// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001150
1151const char* XMLAttribute::Name() const
1152{
1153 return _name.GetStr();
1154}
1155
1156const char* XMLAttribute::Value() const
1157{
1158 return _value.GetStr();
1159}
1160
Lee Thomason6f381b72012-03-02 12:59:39 -08001161char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 if ( !p || !*p ) {
1166 return 0;
1167 }
Lee Thomason22aead12012-01-23 13:29:35 -08001168
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 // Skip white space before =
1170 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001171 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 return 0;
1173 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001174
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 ++p; // move up to opening quote
1176 p = XMLUtil::SkipWhiteSpace( p );
1177 if ( *p != '\"' && *p != '\'' ) {
1178 return 0;
1179 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001180
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char endTag[2] = { *p, 0 };
1182 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001183
Lee Thomason624d43f2012-10-12 10:58:48 -07001184 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001186}
1187
1188
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001189void XMLAttribute::SetName( const char* n )
1190{
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001192}
1193
1194
Lee Thomason2fa81722012-11-09 12:37:46 -08001195XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::ToInt( Value(), value )) {
1198 return XML_NO_ERROR;
1199 }
1200 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201}
1202
1203
Lee Thomason2fa81722012-11-09 12:37:46 -08001204XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 if ( XMLUtil::ToUnsigned( Value(), value )) {
1207 return XML_NO_ERROR;
1208 }
1209 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210}
1211
1212
Lee Thomason2fa81722012-11-09 12:37:46 -08001213XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( XMLUtil::ToBool( Value(), value )) {
1216 return XML_NO_ERROR;
1217 }
1218 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219}
1220
1221
Lee Thomason2fa81722012-11-09 12:37:46 -08001222XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( XMLUtil::ToFloat( Value(), value )) {
1225 return XML_NO_ERROR;
1226 }
1227 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001228}
1229
1230
Lee Thomason2fa81722012-11-09 12:37:46 -08001231XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( XMLUtil::ToDouble( Value(), value )) {
1234 return XML_NO_ERROR;
1235 }
1236 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001237}
1238
1239
1240void XMLAttribute::SetAttribute( const char* v )
1241{
Lee Thomason624d43f2012-10-12 10:58:48 -07001242 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001243}
1244
1245
Lee Thomason1ff38e02012-02-14 18:18:16 -08001246void XMLAttribute::SetAttribute( int v )
1247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 char buf[BUF_SIZE];
1249 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001251}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001252
1253
1254void XMLAttribute::SetAttribute( unsigned v )
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 char buf[BUF_SIZE];
1257 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001258 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001259}
1260
1261
1262void XMLAttribute::SetAttribute( bool v )
1263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 char buf[BUF_SIZE];
1265 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001266 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001267}
1268
1269void XMLAttribute::SetAttribute( double v )
1270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 char buf[BUF_SIZE];
1272 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001273 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001274}
1275
1276void XMLAttribute::SetAttribute( float v )
1277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 char buf[BUF_SIZE];
1279 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001280 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001281}
1282
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001283
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001284// --------- XMLElement ---------- //
1285XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001286 _closingType( 0 ),
1287 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001288{
1289}
1290
1291
1292XMLElement::~XMLElement()
1293{
Lee Thomason624d43f2012-10-12 10:58:48 -07001294 while( _rootAttribute ) {
1295 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001296 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001299}
1300
1301
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001302const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1303{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001304 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1306 return a;
1307 }
1308 }
1309 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001310}
1311
1312
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001313const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 const XMLAttribute* a = FindAttribute( name );
1316 if ( !a ) {
1317 return 0;
1318 }
1319 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1320 return a->Value();
1321 }
1322 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001323}
1324
1325
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001326const char* XMLElement::GetText() const
1327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001329 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001332}
1333
1334
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001335void XMLElement::SetText( const char* inText )
1336{
Uli Kusterer869bb592014-01-21 01:36:16 +01001337 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001338 FirstChild()->SetValue( inText );
1339 else {
1340 XMLText* theText = GetDocument()->NewText( inText );
1341 InsertFirstChild( theText );
1342 }
1343}
1344
Lee Thomason5bb2d802014-01-24 10:42:57 -08001345
1346void XMLElement::SetText( int v )
1347{
1348 char buf[BUF_SIZE];
1349 XMLUtil::ToStr( v, buf, BUF_SIZE );
1350 SetText( buf );
1351}
1352
1353
1354void XMLElement::SetText( unsigned v )
1355{
1356 char buf[BUF_SIZE];
1357 XMLUtil::ToStr( v, buf, BUF_SIZE );
1358 SetText( buf );
1359}
1360
1361
1362void XMLElement::SetText( bool v )
1363{
1364 char buf[BUF_SIZE];
1365 XMLUtil::ToStr( v, buf, BUF_SIZE );
1366 SetText( buf );
1367}
1368
1369
1370void XMLElement::SetText( float v )
1371{
1372 char buf[BUF_SIZE];
1373 XMLUtil::ToStr( v, buf, BUF_SIZE );
1374 SetText( buf );
1375}
1376
1377
1378void XMLElement::SetText( double v )
1379{
1380 char buf[BUF_SIZE];
1381 XMLUtil::ToStr( v, buf, BUF_SIZE );
1382 SetText( buf );
1383}
1384
1385
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001389 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 return XML_SUCCESS;
1392 }
1393 return XML_CAN_NOT_CONVERT_TEXT;
1394 }
1395 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001396}
1397
1398
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001402 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 return XML_SUCCESS;
1405 }
1406 return XML_CAN_NOT_CONVERT_TEXT;
1407 }
1408 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001409}
1410
1411
MortenMacFly4ee49f12013-01-14 20:03:14 +01001412XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001415 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001416 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 return XML_SUCCESS;
1418 }
1419 return XML_CAN_NOT_CONVERT_TEXT;
1420 }
1421 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
MortenMacFly4ee49f12013-01-14 20:03:14 +01001425XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001428 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001429 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 return XML_SUCCESS;
1431 }
1432 return XML_CAN_NOT_CONVERT_TEXT;
1433 }
1434 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001435}
1436
1437
MortenMacFly4ee49f12013-01-14 20:03:14 +01001438XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001441 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001442 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 return XML_SUCCESS;
1444 }
1445 return XML_CAN_NOT_CONVERT_TEXT;
1446 }
1447 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001448}
1449
1450
1451
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001452XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 XMLAttribute* last = 0;
1455 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001458 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1460 break;
1461 }
1462 }
1463 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001464 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1466 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 }
1470 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 }
1473 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001474 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 }
1476 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
1479
U-Stream\Leeae25a442012-02-17 17:48:16 -08001480void XMLElement::DeleteAttribute( const char* name )
1481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1485 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 }
1488 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001491 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 break;
1493 }
1494 prev = a;
1495 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001496}
1497
1498
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001499char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 const char* start = p;
1502 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001503
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 // Read the attributes.
1505 while( p ) {
1506 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001507 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 return 0;
1510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001511
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001513 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001514 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1516 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001517 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001518
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001521 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 return 0;
1524 }
1525 // There is a minor bug here: if the attribute in the source xml
1526 // document is duplicated, it will not be detected and the
1527 // attribute will be doubly added. However, tracking the 'prevAttribute'
1528 // avoids re-scanning the attribute list. Preferring performance for
1529 // now, may reconsider in the future.
1530 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 }
1533 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001534 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 }
1536 prevAttribute = attrib;
1537 }
1538 // end of the tag
1539 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return p+2; // done; sealed element.
1542 }
1543 // end of the tag
1544 else if ( *p == '>' ) {
1545 ++p;
1546 break;
1547 }
1548 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 return 0;
1551 }
1552 }
1553 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001554}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001555
Dmitry-Mee3225b12014-09-03 11:03:11 +04001556void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1557{
1558 if ( attribute == 0 ) {
1559 return;
1560 }
1561 MemPool* pool = attribute->_memPool;
1562 attribute->~XMLAttribute();
1563 pool->Free( attribute );
1564}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001565
Lee Thomason67d61312012-01-24 16:01:51 -08001566//
1567// <ele></ele>
1568// <ele>foo<b>bar</b></ele>
1569//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001570char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 // Read the element name.
1573 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001574
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 // The closing element is the </element> form. It is
1576 // parsed just like a regular element then deleted from
1577 // the DOM.
1578 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001579 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 ++p;
1581 }
Lee Thomason67d61312012-01-24 16:01:51 -08001582
Lee Thomason624d43f2012-10-12 10:58:48 -07001583 p = _value.ParseName( p );
1584 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 return 0;
1586 }
Lee Thomason67d61312012-01-24 16:01:51 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001589 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 return p;
1591 }
Lee Thomason67d61312012-01-24 16:01:51 -08001592
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 p = XMLNode::ParseDeep( p, strPair );
1594 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001595}
1596
1597
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001598
1599XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001602 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 }
1604 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1605 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1606 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1607 }
1608 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001609}
1610
1611
1612bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1613{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001614 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 const XMLElement* other = compare->ToElement();
1616 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001617
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 const XMLAttribute* a=FirstAttribute();
1619 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001620
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 while ( a && b ) {
1622 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1623 return false;
1624 }
1625 a = a->Next();
1626 b = b->Next();
1627 }
1628 if ( a || b ) {
1629 // different count
1630 return false;
1631 }
1632 return true;
1633 }
1634 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001635}
1636
1637
Lee Thomason751da522012-02-10 08:50:51 -08001638bool XMLElement::Accept( XMLVisitor* visitor ) const
1639{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001640 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001641 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1643 if ( !node->Accept( visitor ) ) {
1644 break;
1645 }
1646 }
1647 }
1648 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001649}
Lee Thomason56bdd022012-02-09 18:16:58 -08001650
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001651
Lee Thomason3f57d272012-01-11 15:30:03 -08001652// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001653
1654// Warning: List must match 'enum XMLError'
1655const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1656 "XML_SUCCESS",
1657 "XML_NO_ATTRIBUTE",
1658 "XML_WRONG_ATTRIBUTE_TYPE",
1659 "XML_ERROR_FILE_NOT_FOUND",
1660 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1661 "XML_ERROR_FILE_READ_ERROR",
1662 "XML_ERROR_ELEMENT_MISMATCH",
1663 "XML_ERROR_PARSING_ELEMENT",
1664 "XML_ERROR_PARSING_ATTRIBUTE",
1665 "XML_ERROR_IDENTIFYING_TAG",
1666 "XML_ERROR_PARSING_TEXT",
1667 "XML_ERROR_PARSING_CDATA",
1668 "XML_ERROR_PARSING_COMMENT",
1669 "XML_ERROR_PARSING_DECLARATION",
1670 "XML_ERROR_PARSING_UNKNOWN",
1671 "XML_ERROR_EMPTY_DOCUMENT",
1672 "XML_ERROR_MISMATCHED_ELEMENT",
1673 "XML_ERROR_PARSING",
1674 "XML_CAN_NOT_CONVERT_TEXT",
1675 "XML_NO_TEXT_NODE"
1676};
1677
1678
Lee Thomason624d43f2012-10-12 10:58:48 -07001679XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 _writeBOM( false ),
1682 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001683 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 _whitespace( whitespace ),
1685 _errorStr1( 0 ),
1686 _errorStr2( 0 ),
1687 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001688{
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001690}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001691
1692
Lee Thomason3f57d272012-01-11 15:30:03 -08001693XMLDocument::~XMLDocument()
1694{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001695 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001696}
1697
1698
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001699void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001700{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001701 DeleteChildren();
1702
Dmitry-Meab37df82014-11-28 12:08:36 +03001703#ifdef DEBUG
1704 const bool hadError = Error();
1705#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 _errorID = XML_NO_ERROR;
1707 _errorStr1 = 0;
1708 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001709
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 delete [] _charBuffer;
1711 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001712
1713#if 0
1714 _textPool.Trace( "text" );
1715 _elementPool.Trace( "element" );
1716 _commentPool.Trace( "comment" );
1717 _attributePool.Trace( "attribute" );
1718#endif
1719
1720#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001721 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001722 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1723 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1724 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1725 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1726 }
1727#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001728}
1729
Lee Thomason3f57d272012-01-11 15:30:03 -08001730
Lee Thomason2c85a712012-01-31 08:24:24 -08001731XMLElement* XMLDocument::NewElement( const char* name )
1732{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001733 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1735 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 ele->SetName( name );
1737 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001738}
1739
1740
Lee Thomason1ff38e02012-02-14 18:18:16 -08001741XMLComment* XMLDocument::NewComment( const char* str )
1742{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001743 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1745 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 comment->SetValue( str );
1747 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001748}
1749
1750
1751XMLText* XMLDocument::NewText( const char* str )
1752{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001753 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1755 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 text->SetValue( str );
1757 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001758}
1759
1760
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001761XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1762{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001763 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1765 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1767 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001768}
1769
1770
1771XMLUnknown* XMLDocument::NewUnknown( const char* str )
1772{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001773 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1775 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 unk->SetValue( str );
1777 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001778}
1779
Dmitry-Me01578db2014-08-19 10:18:48 +04001780static FILE* callfopen( const char* filepath, const char* mode )
1781{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001782 TIXMLASSERT( filepath );
1783 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001784#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1785 FILE* fp = 0;
1786 errno_t err = fopen_s( &fp, filepath, mode );
1787 if ( err ) {
1788 return 0;
1789 }
1790#else
1791 FILE* fp = fopen( filepath, mode );
1792#endif
1793 return fp;
1794}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001795
1796void XMLDocument::DeleteNode( XMLNode* node ) {
1797 TIXMLASSERT( node );
1798 TIXMLASSERT(node->_document == this );
1799 if (node->_parent) {
1800 node->_parent->DeleteChild( node );
1801 }
1802 else {
1803 // Isn't in the tree.
1804 // Use the parent delete.
1805 // Also, we need to mark it tracked: we 'know'
1806 // it was never used.
1807 node->_memPool->SetTracked();
1808 // Call the static XMLNode version:
1809 XMLNode::DeleteNode(node);
1810 }
1811}
1812
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001813
Lee Thomason2fa81722012-11-09 12:37:46 -08001814XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001815{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001816 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001817 FILE* fp = callfopen( filename, "rb" );
1818 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
1822 LoadFile( fp );
1823 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825}
1826
1827
Lee Thomason2fa81722012-11-09 12:37:46 -08001828XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001830 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001831
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001832 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001833 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001834 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1835 return _errorID;
1836 }
1837
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001839 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001841 if ( filelength == -1L ) {
1842 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1843 return _errorID;
1844 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001845
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001846 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001848 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001851
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 _charBuffer = new char[size+1];
1853 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 if ( read != size ) {
1855 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001858
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001860
Dmitry-Me97476b72015-01-01 16:15:57 +03001861 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001863}
1864
1865
Lee Thomason2fa81722012-11-09 12:37:46 -08001866XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001867{
Dmitry-Me01578db2014-08-19 10:18:48 +04001868 FILE* fp = callfopen( filename, "w" );
1869 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 }
1873 SaveFile(fp, compact);
1874 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001876}
1877
1878
Lee Thomason2fa81722012-11-09 12:37:46 -08001879XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 XMLPrinter stream( fp, compact );
1882 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001884}
1885
Lee Thomason1ff38e02012-02-14 18:18:16 -08001886
Lee Thomason2fa81722012-11-09 12:37:46 -08001887XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001888{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001889 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001890
Lee Thomason82d32002014-02-21 22:47:18 -08001891 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 }
1895 if ( len == (size_t)(-1) ) {
1896 len = strlen( p );
1897 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 _charBuffer = new char[ len+1 ];
1899 memcpy( _charBuffer, p, len );
1900 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001901
Dmitry-Me97476b72015-01-01 16:15:57 +03001902 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001903 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001904 // clean up now essentially dangling memory.
1905 // and the parse fail can put objects in the
1906 // pools that are dead and inaccessible.
1907 DeleteChildren();
1908 _elementPool.Clear();
1909 _attributePool.Clear();
1910 _textPool.Clear();
1911 _commentPool.Clear();
1912 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001914}
1915
1916
PKEuS1c5f99e2013-07-06 11:28:39 +02001917void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 XMLPrinter stdStreamer( stdout );
1920 if ( !streamer ) {
1921 streamer = &stdStreamer;
1922 }
1923 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001924}
1925
1926
Lee Thomason2fa81722012-11-09 12:37:46 -08001927void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001928{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001929 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 _errorID = error;
1931 _errorStr1 = str1;
1932 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001933}
1934
Lee Thomason331596e2014-09-11 14:56:43 -07001935const char* XMLDocument::ErrorName() const
1936{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001937 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001938 return _errorNames[_errorID];
1939}
Lee Thomason5cae8972012-01-24 18:03:07 -08001940
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001941void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001942{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001943 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 static const int LEN = 20;
1945 char buf1[LEN] = { 0 };
1946 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001947
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( _errorStr1 ) {
1949 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _errorStr2 ) {
1952 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001954
Lee Thomason331596e2014-09-11 14:56:43 -07001955 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1956 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001958}
1959
Dmitry-Me97476b72015-01-01 16:15:57 +03001960void XMLDocument::Parse()
1961{
1962 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1963 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001964 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001965 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001966 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001967 if ( !*p ) {
1968 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1969 return;
1970 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001971 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001972}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001973
PKEuS1bfb9542013-08-04 13:51:17 +02001974XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 _elementJustOpened( false ),
1976 _firstElement( true ),
1977 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001978 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 _textDepth( -1 ),
1980 _processEntities( true ),
1981 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 _entityFlag[i] = false;
1985 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 }
1987 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001988 const char entityValue = entities[i].value;
1989 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1990 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001991 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001992 _restrictedEntityFlag[(unsigned char)'&'] = true;
1993 _restrictedEntityFlag[(unsigned char)'<'] = true;
1994 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001996}
1997
1998
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001999void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002000{
2001 va_list va;
2002 va_start( va, format );
2003
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 if ( _fp ) {
2005 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 }
2007 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002008#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002009 #if defined(WINCE)
2010 int len = 512;
2011 do {
2012 len = len*2;
2013 char* str = new char[len]();
2014 len = _vsnprintf(str, len, format, va);
2015 delete[] str;
2016 }while (len < 0);
2017 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002018 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002019 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020#else
2021 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002022#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 // Close out and re-start the va-args
2024 va_end( va );
2025 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002026 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002027 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2028#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002029 #if defined(WINCE)
2030 _vsnprintf( p, len+1, format, va );
2031 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002032 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002033 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002034#else
2035 vsnprintf( p, len+1, format, va );
2036#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002038 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002039}
2040
2041
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002042void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002043{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 for( int i=0; i<depth; ++i ) {
2045 Print( " " );
2046 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002047}
2048
2049
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002050void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002051{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 // Look for runs of bytes between entities to print.
2053 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002054
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002056 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 while ( *q ) {
2058 // Remember, char is sometimes signed. (How many times has that bitten me?)
2059 if ( *q > 0 && *q < ENTITY_RANGE ) {
2060 // Check for entities. If one is found, flush
2061 // the stream up until the entity, write the
2062 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002063 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 while ( p < q ) {
2065 Print( "%c", *p );
2066 ++p;
2067 }
2068 for( int i=0; i<NUM_ENTITIES; ++i ) {
2069 if ( entities[i].value == *q ) {
2070 Print( "&%s;", entities[i].pattern );
2071 break;
2072 }
2073 }
2074 ++p;
2075 }
2076 }
2077 ++q;
2078 }
2079 }
2080 // Flush the remaining string. This will be the entire
2081 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 Print( "%s", p );
2084 }
Lee Thomason857b8682012-01-25 17:50:25 -08002085}
2086
U-Stream\Leeae25a442012-02-17 17:48:16 -08002087
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002088void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002091 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 -07002092 Print( "%s", bom );
2093 }
2094 if ( writeDec ) {
2095 PushDeclaration( "xml version=\"1.0\"" );
2096 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002097}
2098
2099
Uli Kusterer593a33d2014-02-01 12:48:51 +01002100void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002101{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002102 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002103 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002104
Uli Kusterer593a33d2014-02-01 12:48:51 +01002105 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002107 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002108 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002111
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 _elementJustOpened = true;
2114 _firstElement = false;
2115 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002116}
2117
2118
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002119void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002120{
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 Print( " %s=\"", name );
2123 PrintString( value, false );
2124 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002125}
2126
2127
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002128void XMLPrinter::PushAttribute( const char* name, int v )
2129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 char buf[BUF_SIZE];
2131 XMLUtil::ToStr( v, buf, BUF_SIZE );
2132 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002133}
2134
2135
2136void XMLPrinter::PushAttribute( const char* name, unsigned v )
2137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 char buf[BUF_SIZE];
2139 XMLUtil::ToStr( v, buf, BUF_SIZE );
2140 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002141}
2142
2143
2144void XMLPrinter::PushAttribute( const char* name, bool v )
2145{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 char buf[BUF_SIZE];
2147 XMLUtil::ToStr( v, buf, BUF_SIZE );
2148 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002149}
2150
2151
2152void XMLPrinter::PushAttribute( const char* name, double v )
2153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 char buf[BUF_SIZE];
2155 XMLUtil::ToStr( v, buf, BUF_SIZE );
2156 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002157}
2158
2159
Uli Kustererca412e82014-02-01 13:35:05 +01002160void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002161{
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 --_depth;
2163 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002164
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 Print( "/>" );
2167 }
2168 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002169 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 }
2173 Print( "</%s>", name );
2174 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002175
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 if ( _textDepth == _depth ) {
2177 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 }
Uli Kustererca412e82014-02-01 13:35:05 +01002179 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 Print( "\n" );
2181 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002183}
2184
2185
Dmitry-Mea092bc12014-12-23 17:57:05 +03002186void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002187{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002188 if ( !_elementJustOpened ) {
2189 return;
2190 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002193}
2194
2195
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002196void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002197{
Lee Thomason624d43f2012-10-12 10:58:48 -07002198 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002199
Dmitry-Mea092bc12014-12-23 17:57:05 +03002200 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 if ( cdata ) {
2202 Print( "<![CDATA[" );
2203 Print( "%s", text );
2204 Print( "]]>" );
2205 }
2206 else {
2207 PrintString( text, true );
2208 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002209}
2210
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002211void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 char buf[BUF_SIZE];
2214 XMLUtil::ToStr( value, buf, BUF_SIZE );
2215 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002216}
2217
2218
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002219void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 char buf[BUF_SIZE];
2222 XMLUtil::ToStr( value, buf, BUF_SIZE );
2223 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002224}
2225
2226
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002227void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 char buf[BUF_SIZE];
2230 XMLUtil::ToStr( value, buf, BUF_SIZE );
2231 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002232}
2233
2234
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002235void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 char buf[BUF_SIZE];
2238 XMLUtil::ToStr( value, buf, BUF_SIZE );
2239 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002240}
2241
2242
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002243void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 char buf[BUF_SIZE];
2246 XMLUtil::ToStr( value, buf, BUF_SIZE );
2247 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002248}
2249
Lee Thomason5cae8972012-01-24 18:03:07 -08002250
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002251void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002252{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002253 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002260}
Lee Thomason751da522012-02-10 08:50:51 -08002261
2262
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002263void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002264{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002265 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002266 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002268 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002272}
2273
2274
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002275void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002276{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002277 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002278 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002280 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002282 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002284}
2285
2286
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002287bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002288{
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 if ( doc.HasBOM() ) {
2291 PushHeader( true, false );
2292 }
2293 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002294}
2295
2296
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002297bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002298{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002299 const XMLElement* parentElem = element.Parent()->ToElement();
2300 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2301 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 while ( attribute ) {
2303 PushAttribute( attribute->Name(), attribute->Value() );
2304 attribute = attribute->Next();
2305 }
2306 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002307}
2308
2309
Uli Kustererca412e82014-02-01 13:35:05 +01002310bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002311{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002312 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002314}
2315
2316
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002317bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 PushText( text.Value(), text.CData() );
2320 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002321}
2322
2323
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002324bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002325{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002326 PushComment( comment.Value() );
2327 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002328}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002329
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002330bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002332 PushDeclaration( declaration.Value() );
2333 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002334}
2335
2336
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002337bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 PushUnknown( unknown.Value() );
2340 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002341}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002342
Lee Thomason685b8952012-11-12 13:00:06 -08002343} // namespace tinyxml2
2344