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