blob: 32ad143db9361923e7d483606e063b5f89a3242d [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;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700231 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400232 TIXMLASSERT( 0 <= len && len <= buflen );
233 TIXMLASSERT( q + len <= p );
234 memcpy( q, buf, len );
235 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 }
237 else {
238 int i=0;
239 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400240 const Entity& entity = entities[i];
241 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
242 && *( p + entity.length + 1 ) == ';' ) {
243 // Found an entity - convert.
244 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400246 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700247 break;
248 }
249 }
250 if ( i == NUM_ENTITIES ) {
251 // fixme: treat as error?
252 ++p;
253 ++q;
254 }
255 }
256 }
257 else {
258 *q = *p;
259 ++p;
260 ++q;
261 }
262 }
263 *q = 0;
264 }
265 // The loop below has plenty going on, and this
266 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700268 CollapseWhitespace();
269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300272 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800274}
275
Lee Thomason2c85a712012-01-31 08:24:24 -0800276
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278
Lee Thomason56bdd022012-02-09 18:16:58 -0800279// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800280
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281const char* XMLUtil::ReadBOM( const char* p, bool* bom )
282{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300283 TIXMLASSERT( p );
284 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700285 *bom = false;
286 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
287 // Check for BOM:
288 if ( *(pu+0) == TIXML_UTF_LEAD_0
289 && *(pu+1) == TIXML_UTF_LEAD_1
290 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
291 *bom = true;
292 p += 3;
293 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300294 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800296}
297
298
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800299void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
300{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 const unsigned long BYTE_MASK = 0xBF;
302 const unsigned long BYTE_MARK = 0x80;
303 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if (input < 0x80) {
306 *length = 1;
307 }
308 else if ( input < 0x800 ) {
309 *length = 2;
310 }
311 else if ( input < 0x10000 ) {
312 *length = 3;
313 }
314 else if ( input < 0x200000 ) {
315 *length = 4;
316 }
317 else {
318 *length = 0; // This code won't covert this correctly anyway.
319 return;
320 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800323
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700324 // Scary scary fall throughs.
325 switch (*length) {
326 case 4:
327 --output;
328 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
329 input >>= 6;
330 case 3:
331 --output;
332 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
333 input >>= 6;
334 case 2:
335 --output;
336 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
337 input >>= 6;
338 case 1:
339 --output;
340 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100341 default:
342 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344}
345
346
347const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 // Presume an entity, and pull it out.
350 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( *(p+1) == '#' && *(p+2) ) {
353 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300354 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 ptrdiff_t delta = 0;
356 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800357 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 if ( *(p+2) == 'x' ) {
360 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300361 const char* q = p+3;
362 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomason7e67bc82015-01-12 14:05:12 -0800366 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800367
Dmitry-Me9f56e122015-01-12 10:07:54 +0300368 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 return 0;
370 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800371 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != 'x' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300377 unsigned int digit;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300379 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700380 }
381 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300382 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 }
384 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300385 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 }
387 else {
388 return 0;
389 }
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300390 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
391 const unsigned int digitScaled = mult * digit;
392 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
393 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300394 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700395 mult *= 16;
396 --q;
397 }
398 }
399 else {
400 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300401 const char* q = p+2;
402 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 return 0;
404 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405
Lee Thomason7e67bc82015-01-12 14:05:12 -0800406 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Dmitry-Me9f56e122015-01-12 10:07:54 +0300408 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 return 0;
410 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800411 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800412
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700413 delta = q-p;
414 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800415
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 while ( *q != '#' ) {
417 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300418 const unsigned int digit = *q - '0';
419 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
420 const unsigned int digitScaled = mult * digit;
421 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
422 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 }
424 else {
425 return 0;
426 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300427 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 mult *= 10;
429 --q;
430 }
431 }
432 // convert the UCS to UTF-8
433 ConvertUTF32ToUTF8( ucs, value, length );
434 return p + delta + 1;
435 }
436 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800437}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800438
439
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700440void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700448 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800457/*
458 ToStr() of a number is a very tricky topic.
459 https://github.com/leethomason/tinyxml2/issues/106
460*/
Lee Thomason21be8822012-07-15 17:27:22 -0700461void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
462{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800463 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700464}
465
466
467void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
468{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800469 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472
473bool XMLUtil::ToInt( const char* str, int* value )
474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
476 return true;
477 }
478 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700479}
480
481bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489bool XMLUtil::ToBool( const char* str, bool* value )
490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 int ival = 0;
492 if ( ToInt( str, &ival )) {
493 *value = (ival==0) ? false : true;
494 return true;
495 }
496 if ( StringEqual( str, "true" ) ) {
497 *value = true;
498 return true;
499 }
500 else if ( StringEqual( str, "false" ) ) {
501 *value = false;
502 return true;
503 }
504 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700505}
506
507
508bool XMLUtil::ToFloat( const char* str, float* value )
509{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
511 return true;
512 }
513 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700514}
515
516bool XMLUtil::ToDouble( const char* str, double* value )
517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
519 return true;
520 }
521 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700522}
523
524
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700525char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800526{
Dmitry-Me02384662015-03-03 16:02:13 +0300527 TIXMLASSERT( node );
528 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400529 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300531 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300532 *node = 0;
533 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 return p;
535 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800536
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800538 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 static const char* xmlHeader = { "<?" };
540 static const char* commentHeader = { "<!--" };
541 static const char* dtdHeader = { "<!" };
542 static const char* cdataHeader = { "<![CDATA[" };
543 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 static const int xmlHeaderLen = 2;
546 static const int commentHeaderLen = 4;
547 static const int dtdHeaderLen = 2;
548 static const int cdataHeaderLen = 9;
549 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800550
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
552 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400553 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300555 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700556 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
557 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 p += xmlHeaderLen;
559 }
560 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300561 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700562 returnNode = new (_commentPool.Alloc()) XMLComment( this );
563 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 p += commentHeaderLen;
565 }
566 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300567 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700568 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p += cdataHeaderLen;
572 text->SetCData( true );
573 }
574 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300575 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700576 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
577 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700578 p += dtdHeaderLen;
579 }
580 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300581 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 returnNode = new (_elementPool.Alloc()) XMLElement( this );
583 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 p += elementHeaderLen;
585 }
586 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300587 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700588 returnNode = new (_textPool.Alloc()) XMLText( this );
589 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 p = start; // Back it up, all the text counts.
591 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592
Dmitry-Me02384662015-03-03 16:02:13 +0300593 TIXMLASSERT( returnNode );
594 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 *node = returnNode;
596 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800597}
598
599
Lee Thomason751da522012-02-10 08:50:51 -0800600bool XMLDocument::Accept( XMLVisitor* visitor ) const
601{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300602 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( visitor->VisitEnter( *this ) ) {
604 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
605 if ( !node->Accept( visitor ) ) {
606 break;
607 }
608 }
609 }
610 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800611}
Lee Thomason56bdd022012-02-09 18:16:58 -0800612
613
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800614// --------- XMLNode ----------- //
615
616XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 _document( doc ),
618 _parent( 0 ),
619 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200620 _prev( 0 ), _next( 0 ),
621 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800623}
624
625
626XMLNode::~XMLNode()
627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 if ( _parent ) {
630 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800632}
633
Michael Daumling21626882013-10-22 17:03:37 +0200634const char* XMLNode::Value() const
635{
636 return _value.GetStr();
637}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800638
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800639void XMLNode::SetValue( const char* str, bool staticMem )
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 }
644 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800647}
648
649
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800650void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800651{
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300653 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700656
Dmitry-Mee3225b12014-09-03 11:03:11 +0400657 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800660}
661
662
663void XMLNode::Unlink( XMLNode* child )
664{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300665 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300666 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 if ( child == _firstChild ) {
668 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 if ( child == _lastChild ) {
671 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 }
Lee Thomasond923c672012-01-23 08:44:25 -0800673
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 if ( child->_prev ) {
675 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 if ( child->_next ) {
678 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700680 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681}
682
683
U-Stream\Leeae25a442012-02-17 17:48:16 -0800684void XMLNode::DeleteChild( XMLNode* node )
685{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300686 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300687 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400689 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800690}
691
692
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
694{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300695 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300696 if ( addThis->_document != _document ) {
697 TIXMLASSERT( false );
698 return 0;
699 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800700 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700701
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 if ( _lastChild ) {
703 TIXMLASSERT( _firstChild );
704 TIXMLASSERT( _lastChild->_next == 0 );
705 _lastChild->_next = addThis;
706 addThis->_prev = _lastChild;
707 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 }
711 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700712 TIXMLASSERT( _firstChild == 0 );
713 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 addThis->_prev = 0;
716 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800720}
721
722
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
724{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300725 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300726 if ( addThis->_document != _document ) {
727 TIXMLASSERT( false );
728 return 0;
729 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800730 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 if ( _firstChild ) {
733 TIXMLASSERT( _lastChild );
734 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800735
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 _firstChild->_prev = addThis;
737 addThis->_next = _firstChild;
738 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800739
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 }
742 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 TIXMLASSERT( _lastChild == 0 );
744 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800745
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 addThis->_prev = 0;
747 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400750 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751}
752
753
754XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
755{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300756 TIXMLASSERT( addThis );
757 if ( addThis->_document != _document ) {
758 TIXMLASSERT( false );
759 return 0;
760 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700761
Dmitry-Meabb2d042014-12-09 12:59:31 +0300762 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700763
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300765 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 return 0;
767 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800768
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 // The last node or the only node.
771 return InsertEndChild( addThis );
772 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800773 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 addThis->_prev = afterThis;
775 addThis->_next = afterThis->_next;
776 afterThis->_next->_prev = addThis;
777 afterThis->_next = addThis;
778 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800780}
781
782
783
784
Lee Thomason56bdd022012-02-09 18:16:58 -0800785const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 XMLElement* element = node->ToElement();
789 if ( element ) {
790 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
791 return element;
792 }
793 }
794 }
795 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800796}
797
798
Lee Thomason56bdd022012-02-09 18:16:58 -0800799const XMLElement* XMLNode::LastChildElement( const char* value ) const
800{
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 XMLElement* element = node->ToElement();
803 if ( element ) {
804 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
805 return element;
806 }
807 }
808 }
809 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800810}
811
812
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800813const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
814{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400815 for( XMLNode* node=this->_next; node; node = node->_next ) {
816 const XMLElement* element = node->ToElement();
817 if ( element
818 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
819 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
821 }
822 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800823}
824
825
826const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
827{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400828 for( XMLNode* node=_prev; node; node = node->_prev ) {
829 const XMLElement* element = node->ToElement();
830 if ( element
831 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
832 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 }
834 }
835 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800836}
837
838
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800839char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800840{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 // This is a recursive method, but thinking about it "at the current level"
842 // it is a pretty simple flat list:
843 // <foo/>
844 // <!-- comment -->
845 //
846 // With a special case:
847 // <foo>
848 // </foo>
849 // <!-- comment -->
850 //
851 // Where the closing element (/foo) *must* be the next thing after the opening
852 // element, and the names must match. BUT the tricky bit is that the closing
853 // element will be read by the child.
854 //
855 // 'endTag' is the end tag for this node, it is returned by a call to a child.
856 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800857
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 while( p && *p ) {
859 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300862 if ( node == 0 ) {
863 break;
864 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800865
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 StrPair endTag;
867 p = node->ParseDeep( p, &endTag );
868 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400869 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 if ( !_document->Error() ) {
871 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 }
873 break;
874 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800875
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400876 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500878 // We read the end tag. Return it to the parent.
879 if ( ele->ClosingType() == XMLElement::CLOSING ) {
880 if ( parentEnd ) {
881 ele->_value.TransferTo( parentEnd );
882 }
883 node->_memPool->SetTracked(); // created and then immediately deleted.
884 DeleteNode( node );
885 return p;
886 }
887
888 // Handle an end tag returned to this level.
889 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400890 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300891 if ( endTag.Empty() ) {
892 if ( ele->ClosingType() == XMLElement::OPEN ) {
893 mismatch = true;
894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300896 else {
897 if ( ele->ClosingType() != XMLElement::OPEN ) {
898 mismatch = true;
899 }
900 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400901 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 }
903 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400904 if ( mismatch ) {
905 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500906 DeleteNode( node );
907 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400908 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 }
JayXondbfdd8f2014-12-12 20:07:14 -0500910 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800913}
914
Dmitry-Mee3225b12014-09-03 11:03:11 +0400915void XMLNode::DeleteNode( XMLNode* node )
916{
917 if ( node == 0 ) {
918 return;
919 }
920 MemPool* pool = node->_memPool;
921 node->~XMLNode();
922 pool->Free( node );
923}
924
Lee Thomason3cebdc42015-01-05 17:16:28 -0800925void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300926{
927 TIXMLASSERT( insertThis );
928 TIXMLASSERT( insertThis->_document == _document );
929
930 if ( insertThis->_parent )
931 insertThis->_parent->Unlink( insertThis );
932 else
933 insertThis->_memPool->SetTracked();
934}
935
Lee Thomason5492a1c2012-01-23 15:32:10 -0800936// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800937char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 const char* start = p;
940 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700941 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 return p;
946 }
947 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700948 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
949 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 flags |= StrPair::COLLAPSE_WHITESPACE;
951 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700952
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( p && *p ) {
955 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300956 }
957 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300958 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 }
960 }
961 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800962}
963
964
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
971 text->SetCData( this->CData() );
972 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973}
974
975
976bool XMLText::ShallowEqual( const XMLNode* compare ) const
977{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400978 const XMLText* text = compare->ToText();
979 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800980}
981
982
Lee Thomason56bdd022012-02-09 18:16:58 -0800983bool XMLText::Accept( XMLVisitor* visitor ) const
984{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300985 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800987}
988
989
Lee Thomason3f57d272012-01-11 15:30:03 -0800990// --------- XMLComment ---------- //
991
Lee Thomasone4422302012-01-20 17:59:50 -0800992XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800993{
994}
995
996
Lee Thomasonce0763e2012-01-11 15:43:54 -0800997XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800998{
Lee Thomason3f57d272012-01-11 15:30:03 -0800999}
1000
1001
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001002char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001003{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 // Comment parses as text.
1005 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001006 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001008 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 }
1010 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001011}
1012
1013
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001014XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
1019 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1020 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001021}
1022
1023
1024bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1025{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001026 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001027 const XMLComment* comment = compare->ToComment();
1028 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001029}
1030
1031
Lee Thomason751da522012-02-10 08:50:51 -08001032bool XMLComment::Accept( XMLVisitor* visitor ) const
1033{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001034 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001036}
Lee Thomason56bdd022012-02-09 18:16:58 -08001037
1038
Lee Thomason50f97b22012-02-11 16:33:40 -08001039// --------- XMLDeclaration ---------- //
1040
1041XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1042{
1043}
1044
1045
1046XMLDeclaration::~XMLDeclaration()
1047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001049}
1050
1051
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001052char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 // Declaration parses as text.
1055 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001056 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001058 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 }
1060 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001061}
1062
1063
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001067 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 }
1069 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1070 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001071}
1072
1073
1074bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1075{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001076 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001077 const XMLDeclaration* declaration = compare->ToDeclaration();
1078 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001079}
1080
1081
1082
Lee Thomason50f97b22012-02-11 16:33:40 -08001083bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1084{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001085 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001087}
1088
1089// --------- XMLUnknown ---------- //
1090
1091XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1092{
1093}
1094
1095
1096XMLUnknown::~XMLUnknown()
1097{
1098}
1099
1100
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001101char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 // Unknown parses as text.
1104 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001105
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
1110 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001111}
1112
1113
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001114XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001117 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 }
1119 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1120 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001121}
1122
1123
1124bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1125{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001126 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001127 const XMLUnknown* unknown = compare->ToUnknown();
1128 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001129}
1130
1131
Lee Thomason50f97b22012-02-11 16:33:40 -08001132bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1133{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001134 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001136}
1137
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001138// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001139
1140const char* XMLAttribute::Name() const
1141{
1142 return _name.GetStr();
1143}
1144
1145const char* XMLAttribute::Value() const
1146{
1147 return _value.GetStr();
1148}
1149
Lee Thomason6f381b72012-03-02 12:59:39 -08001150char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 if ( !p || !*p ) {
1155 return 0;
1156 }
Lee Thomason22aead12012-01-23 13:29:35 -08001157
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 // Skip white space before =
1159 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001160 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 return 0;
1162 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001163
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 ++p; // move up to opening quote
1165 p = XMLUtil::SkipWhiteSpace( p );
1166 if ( *p != '\"' && *p != '\'' ) {
1167 return 0;
1168 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001169
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 char endTag[2] = { *p, 0 };
1171 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001172
Lee Thomason624d43f2012-10-12 10:58:48 -07001173 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001175}
1176
1177
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001178void XMLAttribute::SetName( const char* n )
1179{
Lee Thomason624d43f2012-10-12 10:58:48 -07001180 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001181}
1182
1183
Lee Thomason2fa81722012-11-09 12:37:46 -08001184XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::ToInt( Value(), value )) {
1187 return XML_NO_ERROR;
1188 }
1189 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190}
1191
1192
Lee Thomason2fa81722012-11-09 12:37:46 -08001193XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( XMLUtil::ToUnsigned( Value(), value )) {
1196 return XML_NO_ERROR;
1197 }
1198 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001199}
1200
1201
Lee Thomason2fa81722012-11-09 12:37:46 -08001202XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( XMLUtil::ToBool( Value(), value )) {
1205 return XML_NO_ERROR;
1206 }
1207 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208}
1209
1210
Lee Thomason2fa81722012-11-09 12:37:46 -08001211XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 if ( XMLUtil::ToFloat( Value(), value )) {
1214 return XML_NO_ERROR;
1215 }
1216 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001217}
1218
1219
Lee Thomason2fa81722012-11-09 12:37:46 -08001220XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( XMLUtil::ToDouble( Value(), value )) {
1223 return XML_NO_ERROR;
1224 }
1225 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001226}
1227
1228
1229void XMLAttribute::SetAttribute( const char* v )
1230{
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001232}
1233
1234
Lee Thomason1ff38e02012-02-14 18:18:16 -08001235void XMLAttribute::SetAttribute( int v )
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 char buf[BUF_SIZE];
1238 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001240}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241
1242
1243void XMLAttribute::SetAttribute( unsigned v )
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 char buf[BUF_SIZE];
1246 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
1250
1251void XMLAttribute::SetAttribute( bool v )
1252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 char buf[BUF_SIZE];
1254 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001256}
1257
1258void XMLAttribute::SetAttribute( double v )
1259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 char buf[BUF_SIZE];
1261 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001263}
1264
1265void XMLAttribute::SetAttribute( float 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
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001272
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001273// --------- XMLElement ---------- //
1274XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 _closingType( 0 ),
1276 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001277{
1278}
1279
1280
1281XMLElement::~XMLElement()
1282{
Lee Thomason624d43f2012-10-12 10:58:48 -07001283 while( _rootAttribute ) {
1284 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001285 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001286 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001288}
1289
1290
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001291const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1292{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001293 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1295 return a;
1296 }
1297 }
1298 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001299}
1300
1301
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001302const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 const XMLAttribute* a = FindAttribute( name );
1305 if ( !a ) {
1306 return 0;
1307 }
1308 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1309 return a->Value();
1310 }
1311 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001312}
1313
1314
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001315const char* XMLElement::GetText() const
1316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001318 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 }
1320 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001321}
1322
1323
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001324void XMLElement::SetText( const char* inText )
1325{
Uli Kusterer869bb592014-01-21 01:36:16 +01001326 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001327 FirstChild()->SetValue( inText );
1328 else {
1329 XMLText* theText = GetDocument()->NewText( inText );
1330 InsertFirstChild( theText );
1331 }
1332}
1333
Lee Thomason5bb2d802014-01-24 10:42:57 -08001334
1335void XMLElement::SetText( int v )
1336{
1337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( v, buf, BUF_SIZE );
1339 SetText( buf );
1340}
1341
1342
1343void XMLElement::SetText( unsigned v )
1344{
1345 char buf[BUF_SIZE];
1346 XMLUtil::ToStr( v, buf, BUF_SIZE );
1347 SetText( buf );
1348}
1349
1350
1351void XMLElement::SetText( bool v )
1352{
1353 char buf[BUF_SIZE];
1354 XMLUtil::ToStr( v, buf, BUF_SIZE );
1355 SetText( buf );
1356}
1357
1358
1359void XMLElement::SetText( float v )
1360{
1361 char buf[BUF_SIZE];
1362 XMLUtil::ToStr( v, buf, BUF_SIZE );
1363 SetText( buf );
1364}
1365
1366
1367void XMLElement::SetText( double v )
1368{
1369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
1371 SetText( buf );
1372}
1373
1374
MortenMacFly4ee49f12013-01-14 20:03:14 +01001375XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001376{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001378 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001379 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 return XML_SUCCESS;
1381 }
1382 return XML_CAN_NOT_CONVERT_TEXT;
1383 }
1384 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001385}
1386
1387
MortenMacFly4ee49f12013-01-14 20:03:14 +01001388XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001391 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001392 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 return XML_SUCCESS;
1394 }
1395 return XML_CAN_NOT_CONVERT_TEXT;
1396 }
1397 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001398}
1399
1400
MortenMacFly4ee49f12013-01-14 20:03:14 +01001401XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001404 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001405 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 return XML_SUCCESS;
1407 }
1408 return XML_CAN_NOT_CONVERT_TEXT;
1409 }
1410 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001411}
1412
1413
MortenMacFly4ee49f12013-01-14 20:03:14 +01001414XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001417 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001418 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 return XML_SUCCESS;
1420 }
1421 return XML_CAN_NOT_CONVERT_TEXT;
1422 }
1423 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001424}
1425
1426
MortenMacFly4ee49f12013-01-14 20:03:14 +01001427XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001430 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001431 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 return XML_SUCCESS;
1433 }
1434 return XML_CAN_NOT_CONVERT_TEXT;
1435 }
1436 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001437}
1438
1439
1440
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 XMLAttribute* last = 0;
1444 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1449 break;
1450 }
1451 }
1452 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001453 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1455 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001463 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
1465 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001466}
1467
1468
U-Stream\Leeae25a442012-02-17 17:48:16 -08001469void XMLElement::DeleteAttribute( const char* name )
1470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1474 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 }
1477 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001480 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 break;
1482 }
1483 prev = a;
1484 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001485}
1486
1487
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001488char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 const char* start = p;
1491 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001492
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 // Read the attributes.
1494 while( p ) {
1495 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001496 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 return 0;
1499 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001500
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001502 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001503 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1505 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001506 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001507
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001510 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return 0;
1513 }
1514 // There is a minor bug here: if the attribute in the source xml
1515 // document is duplicated, it will not be detected and the
1516 // attribute will be doubly added. However, tracking the 'prevAttribute'
1517 // avoids re-scanning the attribute list. Preferring performance for
1518 // now, may reconsider in the future.
1519 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 }
1522 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 }
1525 prevAttribute = attrib;
1526 }
1527 // end of the tag
1528 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001529 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 return p+2; // done; sealed element.
1531 }
1532 // end of the tag
1533 else if ( *p == '>' ) {
1534 ++p;
1535 break;
1536 }
1537 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001538 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 return 0;
1540 }
1541 }
1542 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001543}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001544
Dmitry-Mee3225b12014-09-03 11:03:11 +04001545void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1546{
1547 if ( attribute == 0 ) {
1548 return;
1549 }
1550 MemPool* pool = attribute->_memPool;
1551 attribute->~XMLAttribute();
1552 pool->Free( attribute );
1553}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001554
Lee Thomason67d61312012-01-24 16:01:51 -08001555//
1556// <ele></ele>
1557// <ele>foo<b>bar</b></ele>
1558//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001559char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 // Read the element name.
1562 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001563
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 // The closing element is the </element> form. It is
1565 // parsed just like a regular element then deleted from
1566 // the DOM.
1567 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 ++p;
1570 }
Lee Thomason67d61312012-01-24 16:01:51 -08001571
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 p = _value.ParseName( p );
1573 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 return 0;
1575 }
Lee Thomason67d61312012-01-24 16:01:51 -08001576
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001578 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 return p;
1580 }
Lee Thomason67d61312012-01-24 16:01:51 -08001581
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 p = XMLNode::ParseDeep( p, strPair );
1583 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001584}
1585
1586
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001587
1588XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001591 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 }
1593 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1594 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1595 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1596 }
1597 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001598}
1599
1600
1601bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1602{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001603 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 const XMLElement* other = compare->ToElement();
1605 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001606
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 const XMLAttribute* a=FirstAttribute();
1608 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001609
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 while ( a && b ) {
1611 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1612 return false;
1613 }
1614 a = a->Next();
1615 b = b->Next();
1616 }
1617 if ( a || b ) {
1618 // different count
1619 return false;
1620 }
1621 return true;
1622 }
1623 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624}
1625
1626
Lee Thomason751da522012-02-10 08:50:51 -08001627bool XMLElement::Accept( XMLVisitor* visitor ) const
1628{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001629 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001630 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1632 if ( !node->Accept( visitor ) ) {
1633 break;
1634 }
1635 }
1636 }
1637 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001638}
Lee Thomason56bdd022012-02-09 18:16:58 -08001639
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001640
Lee Thomason3f57d272012-01-11 15:30:03 -08001641// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001642
1643// Warning: List must match 'enum XMLError'
1644const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1645 "XML_SUCCESS",
1646 "XML_NO_ATTRIBUTE",
1647 "XML_WRONG_ATTRIBUTE_TYPE",
1648 "XML_ERROR_FILE_NOT_FOUND",
1649 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1650 "XML_ERROR_FILE_READ_ERROR",
1651 "XML_ERROR_ELEMENT_MISMATCH",
1652 "XML_ERROR_PARSING_ELEMENT",
1653 "XML_ERROR_PARSING_ATTRIBUTE",
1654 "XML_ERROR_IDENTIFYING_TAG",
1655 "XML_ERROR_PARSING_TEXT",
1656 "XML_ERROR_PARSING_CDATA",
1657 "XML_ERROR_PARSING_COMMENT",
1658 "XML_ERROR_PARSING_DECLARATION",
1659 "XML_ERROR_PARSING_UNKNOWN",
1660 "XML_ERROR_EMPTY_DOCUMENT",
1661 "XML_ERROR_MISMATCHED_ELEMENT",
1662 "XML_ERROR_PARSING",
1663 "XML_CAN_NOT_CONVERT_TEXT",
1664 "XML_NO_TEXT_NODE"
1665};
1666
1667
Lee Thomason624d43f2012-10-12 10:58:48 -07001668XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _writeBOM( false ),
1671 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001672 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _whitespace( whitespace ),
1674 _errorStr1( 0 ),
1675 _errorStr2( 0 ),
1676 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001677{
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001679}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001680
1681
Lee Thomason3f57d272012-01-11 15:30:03 -08001682XMLDocument::~XMLDocument()
1683{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001684 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001685}
1686
1687
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001688void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001689{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001690 DeleteChildren();
1691
Dmitry-Meab37df82014-11-28 12:08:36 +03001692#ifdef DEBUG
1693 const bool hadError = Error();
1694#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 _errorID = XML_NO_ERROR;
1696 _errorStr1 = 0;
1697 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001698
Lee Thomason624d43f2012-10-12 10:58:48 -07001699 delete [] _charBuffer;
1700 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001701
1702#if 0
1703 _textPool.Trace( "text" );
1704 _elementPool.Trace( "element" );
1705 _commentPool.Trace( "comment" );
1706 _attributePool.Trace( "attribute" );
1707#endif
1708
1709#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001710 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001711 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1712 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1713 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1714 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1715 }
1716#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001717}
1718
Lee Thomason3f57d272012-01-11 15:30:03 -08001719
Lee Thomason2c85a712012-01-31 08:24:24 -08001720XMLElement* XMLDocument::NewElement( const char* name )
1721{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001722 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1724 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 ele->SetName( name );
1726 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001727}
1728
1729
Lee Thomason1ff38e02012-02-14 18:18:16 -08001730XMLComment* XMLDocument::NewComment( const char* str )
1731{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001732 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1734 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 comment->SetValue( str );
1736 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001737}
1738
1739
1740XMLText* XMLDocument::NewText( const char* str )
1741{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001742 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1744 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 text->SetValue( str );
1746 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001747}
1748
1749
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001750XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1751{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001752 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1754 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1756 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001757}
1758
1759
1760XMLUnknown* XMLDocument::NewUnknown( const char* str )
1761{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001762 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1764 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 unk->SetValue( str );
1766 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001767}
1768
Dmitry-Me01578db2014-08-19 10:18:48 +04001769static FILE* callfopen( const char* filepath, const char* mode )
1770{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001771 TIXMLASSERT( filepath );
1772 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001773#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1774 FILE* fp = 0;
1775 errno_t err = fopen_s( &fp, filepath, mode );
1776 if ( err ) {
1777 return 0;
1778 }
1779#else
1780 FILE* fp = fopen( filepath, mode );
1781#endif
1782 return fp;
1783}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001784
1785void XMLDocument::DeleteNode( XMLNode* node ) {
1786 TIXMLASSERT( node );
1787 TIXMLASSERT(node->_document == this );
1788 if (node->_parent) {
1789 node->_parent->DeleteChild( node );
1790 }
1791 else {
1792 // Isn't in the tree.
1793 // Use the parent delete.
1794 // Also, we need to mark it tracked: we 'know'
1795 // it was never used.
1796 node->_memPool->SetTracked();
1797 // Call the static XMLNode version:
1798 XMLNode::DeleteNode(node);
1799 }
1800}
1801
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001802
Lee Thomason2fa81722012-11-09 12:37:46 -08001803XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001804{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001805 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001806 FILE* fp = callfopen( filename, "rb" );
1807 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 }
1811 LoadFile( fp );
1812 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001813 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001814}
1815
1816
Lee Thomason2fa81722012-11-09 12:37:46 -08001817XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001818{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001819 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001820
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001821 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001822 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001823 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1824 return _errorID;
1825 }
1826
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001828 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001830 if ( filelength == -1L ) {
1831 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1832 return _errorID;
1833 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001835 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001837 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001840
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 _charBuffer = new char[size+1];
1842 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 if ( read != size ) {
1844 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001847
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001849
Dmitry-Me97476b72015-01-01 16:15:57 +03001850 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001852}
1853
1854
Lee Thomason2fa81722012-11-09 12:37:46 -08001855XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001856{
Dmitry-Me01578db2014-08-19 10:18:48 +04001857 FILE* fp = callfopen( filename, "w" );
1858 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 }
1862 SaveFile(fp, compact);
1863 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001865}
1866
1867
Lee Thomason2fa81722012-11-09 12:37:46 -08001868XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001869{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 XMLPrinter stream( fp, compact );
1871 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001873}
1874
Lee Thomason1ff38e02012-02-14 18:18:16 -08001875
Lee Thomason2fa81722012-11-09 12:37:46 -08001876XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001877{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001878 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001879
Lee Thomason82d32002014-02-21 22:47:18 -08001880 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 if ( len == (size_t)(-1) ) {
1885 len = strlen( p );
1886 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 _charBuffer = new char[ len+1 ];
1888 memcpy( _charBuffer, p, len );
1889 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001890
Dmitry-Me97476b72015-01-01 16:15:57 +03001891 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001892 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001893 // clean up now essentially dangling memory.
1894 // and the parse fail can put objects in the
1895 // pools that are dead and inaccessible.
1896 DeleteChildren();
1897 _elementPool.Clear();
1898 _attributePool.Clear();
1899 _textPool.Clear();
1900 _commentPool.Clear();
1901 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001903}
1904
1905
PKEuS1c5f99e2013-07-06 11:28:39 +02001906void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 XMLPrinter stdStreamer( stdout );
1909 if ( !streamer ) {
1910 streamer = &stdStreamer;
1911 }
1912 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001913}
1914
1915
Lee Thomason2fa81722012-11-09 12:37:46 -08001916void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001917{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001918 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 _errorID = error;
1920 _errorStr1 = str1;
1921 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001922}
1923
Lee Thomason331596e2014-09-11 14:56:43 -07001924const char* XMLDocument::ErrorName() const
1925{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001926 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001927 return _errorNames[_errorID];
1928}
Lee Thomason5cae8972012-01-24 18:03:07 -08001929
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001930void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001931{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001932 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 static const int LEN = 20;
1934 char buf1[LEN] = { 0 };
1935 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001936
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 if ( _errorStr1 ) {
1938 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 if ( _errorStr2 ) {
1941 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001942 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943
Lee Thomason331596e2014-09-11 14:56:43 -07001944 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1945 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001947}
1948
Dmitry-Me97476b72015-01-01 16:15:57 +03001949void XMLDocument::Parse()
1950{
1951 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1952 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001953 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001954 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001955 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001956 if ( !*p ) {
1957 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1958 return;
1959 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001960 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001961}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001962
PKEuS1bfb9542013-08-04 13:51:17 +02001963XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _elementJustOpened( false ),
1965 _firstElement( true ),
1966 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001967 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 _textDepth( -1 ),
1969 _processEntities( true ),
1970 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001971{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001973 _entityFlag[i] = false;
1974 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 }
1976 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001977 const char entityValue = entities[i].value;
1978 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1979 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001981 _restrictedEntityFlag[(unsigned char)'&'] = true;
1982 _restrictedEntityFlag[(unsigned char)'<'] = true;
1983 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001985}
1986
1987
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001988void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001989{
1990 va_list va;
1991 va_start( va, format );
1992
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 if ( _fp ) {
1994 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 }
1996 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001997#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001998 #if defined(WINCE)
1999 int len = 512;
2000 do {
2001 len = len*2;
2002 char* str = new char[len]();
2003 len = _vsnprintf(str, len, format, va);
2004 delete[] str;
2005 }while (len < 0);
2006 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002007 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002008 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009#else
2010 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002011#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 // Close out and re-start the va-args
2013 va_end( va );
2014 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002015 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002016 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2017#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002018 #if defined(WINCE)
2019 _vsnprintf( p, len+1, format, va );
2020 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002021 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002022 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002023#else
2024 vsnprintf( p, len+1, format, va );
2025#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002027 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002028}
2029
2030
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002031void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 for( int i=0; i<depth; ++i ) {
2034 Print( " " );
2035 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002036}
2037
2038
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002039void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 // Look for runs of bytes between entities to print.
2042 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002045 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 while ( *q ) {
2047 // Remember, char is sometimes signed. (How many times has that bitten me?)
2048 if ( *q > 0 && *q < ENTITY_RANGE ) {
2049 // Check for entities. If one is found, flush
2050 // the stream up until the entity, write the
2051 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002052 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 while ( p < q ) {
2054 Print( "%c", *p );
2055 ++p;
2056 }
2057 for( int i=0; i<NUM_ENTITIES; ++i ) {
2058 if ( entities[i].value == *q ) {
2059 Print( "&%s;", entities[i].pattern );
2060 break;
2061 }
2062 }
2063 ++p;
2064 }
2065 }
2066 ++q;
2067 }
2068 }
2069 // Flush the remaining string. This will be the entire
2070 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002071 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 Print( "%s", p );
2073 }
Lee Thomason857b8682012-01-25 17:50:25 -08002074}
2075
U-Stream\Leeae25a442012-02-17 17:48:16 -08002076
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002077void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002080 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 -07002081 Print( "%s", bom );
2082 }
2083 if ( writeDec ) {
2084 PushDeclaration( "xml version=\"1.0\"" );
2085 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002086}
2087
2088
Uli Kusterer593a33d2014-02-01 12:48:51 +01002089void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002090{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002091 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002093
Uli Kusterer593a33d2014-02-01 12:48:51 +01002094 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002096 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002097 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002098 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002100
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002102 _elementJustOpened = true;
2103 _firstElement = false;
2104 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002105}
2106
2107
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002108void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002109{
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 Print( " %s=\"", name );
2112 PrintString( value, false );
2113 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002114}
2115
2116
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002117void XMLPrinter::PushAttribute( const char* name, int v )
2118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( v, buf, BUF_SIZE );
2121 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
2124
2125void XMLPrinter::PushAttribute( const char* name, unsigned v )
2126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 char buf[BUF_SIZE];
2128 XMLUtil::ToStr( v, buf, BUF_SIZE );
2129 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002130}
2131
2132
2133void XMLPrinter::PushAttribute( const char* name, bool v )
2134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 char buf[BUF_SIZE];
2136 XMLUtil::ToStr( v, buf, BUF_SIZE );
2137 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002138}
2139
2140
2141void XMLPrinter::PushAttribute( const char* name, double v )
2142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 char buf[BUF_SIZE];
2144 XMLUtil::ToStr( v, buf, BUF_SIZE );
2145 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002146}
2147
2148
Uli Kustererca412e82014-02-01 13:35:05 +01002149void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002150{
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 --_depth;
2152 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002153
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 Print( "/>" );
2156 }
2157 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002158 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 }
2162 Print( "</%s>", name );
2163 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002164
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 if ( _textDepth == _depth ) {
2166 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 }
Uli Kustererca412e82014-02-01 13:35:05 +01002168 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 Print( "\n" );
2170 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002172}
2173
2174
Dmitry-Mea092bc12014-12-23 17:57:05 +03002175void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002176{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002177 if ( !_elementJustOpened ) {
2178 return;
2179 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002182}
2183
2184
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002185void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002186{
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002188
Dmitry-Mea092bc12014-12-23 17:57:05 +03002189 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 if ( cdata ) {
2191 Print( "<![CDATA[" );
2192 Print( "%s", text );
2193 Print( "]]>" );
2194 }
2195 else {
2196 PrintString( text, true );
2197 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002198}
2199
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002200void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 char buf[BUF_SIZE];
2203 XMLUtil::ToStr( value, buf, BUF_SIZE );
2204 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002205}
2206
2207
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002208void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 char buf[BUF_SIZE];
2211 XMLUtil::ToStr( value, buf, BUF_SIZE );
2212 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002213}
2214
2215
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002216void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 char buf[BUF_SIZE];
2219 XMLUtil::ToStr( value, buf, BUF_SIZE );
2220 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002221}
2222
2223
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002224void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 char buf[BUF_SIZE];
2227 XMLUtil::ToStr( value, buf, BUF_SIZE );
2228 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002229}
2230
2231
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002232void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 char buf[BUF_SIZE];
2235 XMLUtil::ToStr( value, buf, BUF_SIZE );
2236 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002237}
2238
Lee Thomason5cae8972012-01-24 18:03:07 -08002239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002241{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002242 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002249}
Lee Thomason751da522012-02-10 08:50:51 -08002250
2251
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002252void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002253{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002254 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002261}
2262
2263
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002264void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002265{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002266 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002267 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002273}
2274
2275
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002276bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002277{
Lee Thomason624d43f2012-10-12 10:58:48 -07002278 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 if ( doc.HasBOM() ) {
2280 PushHeader( true, false );
2281 }
2282 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002283}
2284
2285
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002286bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002287{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002288 const XMLElement* parentElem = element.Parent()->ToElement();
2289 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2290 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 while ( attribute ) {
2292 PushAttribute( attribute->Name(), attribute->Value() );
2293 attribute = attribute->Next();
2294 }
2295 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002296}
2297
2298
Uli Kustererca412e82014-02-01 13:35:05 +01002299bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002300{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002301 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002303}
2304
2305
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002306bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 PushText( text.Value(), text.CData() );
2309 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002310}
2311
2312
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002313bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 PushComment( comment.Value() );
2316 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002317}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002318
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002319bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002321 PushDeclaration( declaration.Value() );
2322 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002323}
2324
2325
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002326bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002328 PushUnknown( unknown.Value() );
2329 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002330}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002331
Lee Thomason685b8952012-11-12 13:00:06 -08002332} // namespace tinyxml2
2333