blob: 66fa56090b6d11ee3137c93f3e0d0fdb2aa666b4 [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' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700377 unsigned int digit = 0;
378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300380 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700381 }
382 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300383 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 }
385 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300386 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 }
388 else {
389 return 0;
390 }
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300391 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
Lee Thomason7265b762015-03-15 16:11:47 -0700392 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300393 const unsigned int digitScaled = mult * digit;
394 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
395 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300396 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 mult *= 16;
398 --q;
399 }
400 }
401 else {
402 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300403 const char* q = p+2;
404 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 return 0;
406 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomason7e67bc82015-01-12 14:05:12 -0800408 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800409
Dmitry-Me9f56e122015-01-12 10:07:54 +0300410 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 return 0;
412 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800413 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800414
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700415 delta = q-p;
416 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800417
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700418 while ( *q != '#' ) {
419 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300420 const unsigned int digit = *q - '0';
421 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
422 const unsigned int digitScaled = mult * digit;
423 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
424 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 }
426 else {
427 return 0;
428 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300429 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 mult *= 10;
431 --q;
432 }
433 }
434 // convert the UCS to UTF-8
435 ConvertUTF32ToUTF8( ucs, value, length );
436 return p + delta + 1;
437 }
438 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800439}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800440
441
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700442void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700444 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700445}
446
447
448void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700451}
452
453
454void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700457}
458
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800459/*
460 ToStr() of a number is a very tricky topic.
461 https://github.com/leethomason/tinyxml2/issues/106
462*/
Lee Thomason21be8822012-07-15 17:27:22 -0700463void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
464{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800465 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468
469void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
470{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800471 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474
475bool XMLUtil::ToInt( const char* str, int* value )
476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
478 return true;
479 }
480 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700481}
482
483bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
484{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
486 return true;
487 }
488 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700489}
490
491bool XMLUtil::ToBool( const char* str, bool* value )
492{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 int ival = 0;
494 if ( ToInt( str, &ival )) {
495 *value = (ival==0) ? false : true;
496 return true;
497 }
498 if ( StringEqual( str, "true" ) ) {
499 *value = true;
500 return true;
501 }
502 else if ( StringEqual( str, "false" ) ) {
503 *value = false;
504 return true;
505 }
506 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700507}
508
509
510bool XMLUtil::ToFloat( const char* str, float* value )
511{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
513 return true;
514 }
515 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700516}
517
518bool XMLUtil::ToDouble( const char* str, double* value )
519{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
521 return true;
522 }
523 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700524}
525
526
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700527char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528{
Dmitry-Me02384662015-03-03 16:02:13 +0300529 TIXMLASSERT( node );
530 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400531 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300533 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300534 *node = 0;
535 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 return p;
537 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800538
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800540 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 static const char* xmlHeader = { "<?" };
542 static const char* commentHeader = { "<!--" };
543 static const char* dtdHeader = { "<!" };
544 static const char* cdataHeader = { "<![CDATA[" };
545 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800546
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 static const int xmlHeaderLen = 2;
548 static const int commentHeaderLen = 4;
549 static const int dtdHeaderLen = 2;
550 static const int cdataHeaderLen = 9;
551 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800552
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
554 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400555 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300557 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
559 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p += xmlHeaderLen;
561 }
562 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300563 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_commentPool.Alloc()) XMLComment( this );
565 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p += commentHeaderLen;
567 }
568 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300569 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700572 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 p += cdataHeaderLen;
574 text->SetCData( true );
575 }
576 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300577 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700578 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
579 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 p += dtdHeaderLen;
581 }
582 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300583 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700584 returnNode = new (_elementPool.Alloc()) XMLElement( this );
585 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700586 p += elementHeaderLen;
587 }
588 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300589 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700590 returnNode = new (_textPool.Alloc()) XMLText( this );
591 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 p = start; // Back it up, all the text counts.
593 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800594
Dmitry-Me02384662015-03-03 16:02:13 +0300595 TIXMLASSERT( returnNode );
596 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 *node = returnNode;
598 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800599}
600
601
Lee Thomason751da522012-02-10 08:50:51 -0800602bool XMLDocument::Accept( XMLVisitor* visitor ) const
603{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300604 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 if ( visitor->VisitEnter( *this ) ) {
606 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
607 if ( !node->Accept( visitor ) ) {
608 break;
609 }
610 }
611 }
612 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800613}
Lee Thomason56bdd022012-02-09 18:16:58 -0800614
615
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800616// --------- XMLNode ----------- //
617
618XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700619 _document( doc ),
620 _parent( 0 ),
621 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200622 _prev( 0 ), _next( 0 ),
623 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800624{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800625}
626
627
628XMLNode::~XMLNode()
629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( _parent ) {
632 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800634}
635
Michael Daumling21626882013-10-22 17:03:37 +0200636const char* XMLNode::Value() const
637{
638 return _value.GetStr();
639}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800640
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800641void XMLNode::SetValue( const char* str, bool staticMem )
642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 }
646 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800649}
650
651
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800652void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800653{
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300655 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700658
Dmitry-Mee3225b12014-09-03 11:03:11 +0400659 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800662}
663
664
665void XMLNode::Unlink( XMLNode* child )
666{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300667 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300668 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 if ( child == _firstChild ) {
670 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 if ( child == _lastChild ) {
673 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 }
Lee Thomasond923c672012-01-23 08:44:25 -0800675
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 if ( child->_prev ) {
677 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 if ( child->_next ) {
680 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700682 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800683}
684
685
U-Stream\Leeae25a442012-02-17 17:48:16 -0800686void XMLNode::DeleteChild( XMLNode* node )
687{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300688 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300689 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400691 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800692}
693
694
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
696{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300697 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300698 if ( addThis->_document != _document ) {
699 TIXMLASSERT( false );
700 return 0;
701 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800702 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700703
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 if ( _lastChild ) {
705 TIXMLASSERT( _firstChild );
706 TIXMLASSERT( _lastChild->_next == 0 );
707 _lastChild->_next = addThis;
708 addThis->_prev = _lastChild;
709 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
713 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 TIXMLASSERT( _firstChild == 0 );
715 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 addThis->_prev = 0;
718 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722}
723
724
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
726{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300727 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300728 if ( addThis->_document != _document ) {
729 TIXMLASSERT( false );
730 return 0;
731 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800732 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700733
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 if ( _firstChild ) {
735 TIXMLASSERT( _lastChild );
736 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _firstChild->_prev = addThis;
739 addThis->_next = _firstChild;
740 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800741
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 }
744 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 TIXMLASSERT( _lastChild == 0 );
746 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800747
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 addThis->_prev = 0;
749 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400752 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753}
754
755
756XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
757{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300758 TIXMLASSERT( addThis );
759 if ( addThis->_document != _document ) {
760 TIXMLASSERT( false );
761 return 0;
762 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700763
Dmitry-Meabb2d042014-12-09 12:59:31 +0300764 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700765
Lee Thomason624d43f2012-10-12 10:58:48 -0700766 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300767 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 return 0;
769 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800770
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 // The last node or the only node.
773 return InsertEndChild( addThis );
774 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800775 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 addThis->_prev = afterThis;
777 addThis->_next = afterThis->_next;
778 afterThis->_next->_prev = addThis;
779 afterThis->_next = addThis;
780 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800782}
783
784
785
786
Lee Thomason56bdd022012-02-09 18:16:58 -0800787const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800788{
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 XMLElement* element = node->ToElement();
791 if ( element ) {
792 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
793 return element;
794 }
795 }
796 }
797 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800798}
799
800
Lee Thomason56bdd022012-02-09 18:16:58 -0800801const XMLElement* XMLNode::LastChildElement( const char* value ) const
802{
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 XMLElement* element = node->ToElement();
805 if ( element ) {
806 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
807 return element;
808 }
809 }
810 }
811 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800812}
813
814
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800815const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
816{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400817 for( XMLNode* node=this->_next; node; node = node->_next ) {
818 const XMLElement* element = node->ToElement();
819 if ( element
820 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
821 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 }
824 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800825}
826
827
828const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
829{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400830 for( XMLNode* node=_prev; node; node = node->_prev ) {
831 const XMLElement* element = node->ToElement();
832 if ( element
833 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
834 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
836 }
837 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800838}
839
840
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800841char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800842{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 // This is a recursive method, but thinking about it "at the current level"
844 // it is a pretty simple flat list:
845 // <foo/>
846 // <!-- comment -->
847 //
848 // With a special case:
849 // <foo>
850 // </foo>
851 // <!-- comment -->
852 //
853 // Where the closing element (/foo) *must* be the next thing after the opening
854 // element, and the names must match. BUT the tricky bit is that the closing
855 // element will be read by the child.
856 //
857 // 'endTag' is the end tag for this node, it is returned by a call to a child.
858 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800859
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 while( p && *p ) {
861 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800862
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300864 if ( node == 0 ) {
865 break;
866 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800867
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 StrPair endTag;
869 p = node->ParseDeep( p, &endTag );
870 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400871 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( !_document->Error() ) {
873 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 }
875 break;
876 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800877
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400878 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500880 // We read the end tag. Return it to the parent.
881 if ( ele->ClosingType() == XMLElement::CLOSING ) {
882 if ( parentEnd ) {
883 ele->_value.TransferTo( parentEnd );
884 }
885 node->_memPool->SetTracked(); // created and then immediately deleted.
886 DeleteNode( node );
887 return p;
888 }
889
890 // Handle an end tag returned to this level.
891 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300893 if ( endTag.Empty() ) {
894 if ( ele->ClosingType() == XMLElement::OPEN ) {
895 mismatch = true;
896 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300898 else {
899 if ( ele->ClosingType() != XMLElement::OPEN ) {
900 mismatch = true;
901 }
902 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400903 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 }
905 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400906 if ( mismatch ) {
907 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500908 DeleteNode( node );
909 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400910 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
JayXondbfdd8f2014-12-12 20:07:14 -0500912 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 }
914 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800915}
916
Dmitry-Mee3225b12014-09-03 11:03:11 +0400917void XMLNode::DeleteNode( XMLNode* node )
918{
919 if ( node == 0 ) {
920 return;
921 }
922 MemPool* pool = node->_memPool;
923 node->~XMLNode();
924 pool->Free( node );
925}
926
Lee Thomason3cebdc42015-01-05 17:16:28 -0800927void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300928{
929 TIXMLASSERT( insertThis );
930 TIXMLASSERT( insertThis->_document == _document );
931
932 if ( insertThis->_parent )
933 insertThis->_parent->Unlink( insertThis );
934 else
935 insertThis->_memPool->SetTracked();
936}
937
Lee Thomason5492a1c2012-01-23 15:32:10 -0800938// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800939char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 const char* start = p;
942 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 return p;
948 }
949 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700950 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
951 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 flags |= StrPair::COLLAPSE_WHITESPACE;
953 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700954
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( p && *p ) {
957 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300958 }
959 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300960 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 }
962 }
963 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800964}
965
966
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800967XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
968{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700970 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 }
972 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
973 text->SetCData( this->CData() );
974 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800975}
976
977
978bool XMLText::ShallowEqual( const XMLNode* compare ) const
979{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400980 const XMLText* text = compare->ToText();
981 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800982}
983
984
Lee Thomason56bdd022012-02-09 18:16:58 -0800985bool XMLText::Accept( XMLVisitor* visitor ) const
986{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300987 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800989}
990
991
Lee Thomason3f57d272012-01-11 15:30:03 -0800992// --------- XMLComment ---------- //
993
Lee Thomasone4422302012-01-20 17:59:50 -0800994XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800995{
996}
997
998
Lee Thomasonce0763e2012-01-11 15:43:54 -0800999XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001000{
Lee Thomason3f57d272012-01-11 15:30:03 -08001001}
1002
1003
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001004char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001005{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 // Comment parses as text.
1007 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001008 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001010 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
1012 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001013}
1014
1015
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001016XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001019 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 }
1021 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1022 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023}
1024
1025
1026bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1027{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001028 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001029 const XMLComment* comment = compare->ToComment();
1030 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001031}
1032
1033
Lee Thomason751da522012-02-10 08:50:51 -08001034bool XMLComment::Accept( XMLVisitor* visitor ) const
1035{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001036 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001038}
Lee Thomason56bdd022012-02-09 18:16:58 -08001039
1040
Lee Thomason50f97b22012-02-11 16:33:40 -08001041// --------- XMLDeclaration ---------- //
1042
1043XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1044{
1045}
1046
1047
1048XMLDeclaration::~XMLDeclaration()
1049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001051}
1052
1053
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001054char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 // Declaration parses as text.
1057 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001058 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001060 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 }
1062 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
1065
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001066XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1067{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001069 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
1071 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1072 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001073}
1074
1075
1076bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1077{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001078 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001079 const XMLDeclaration* declaration = compare->ToDeclaration();
1080 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001081}
1082
1083
1084
Lee Thomason50f97b22012-02-11 16:33:40 -08001085bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1086{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001087 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001089}
1090
1091// --------- XMLUnknown ---------- //
1092
1093XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1094{
1095}
1096
1097
1098XMLUnknown::~XMLUnknown()
1099{
1100}
1101
1102
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001103char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001104{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 // Unknown parses as text.
1106 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001107
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001110 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001113}
1114
1115
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001116XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001119 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
1121 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1122 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123}
1124
1125
1126bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1127{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001128 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001129 const XMLUnknown* unknown = compare->ToUnknown();
1130 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
Lee Thomason50f97b22012-02-11 16:33:40 -08001134bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1135{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001136 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001138}
1139
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001140// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001141
1142const char* XMLAttribute::Name() const
1143{
1144 return _name.GetStr();
1145}
1146
1147const char* XMLAttribute::Value() const
1148{
1149 return _value.GetStr();
1150}
1151
Lee Thomason6f381b72012-03-02 12:59:39 -08001152char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 if ( !p || !*p ) {
1157 return 0;
1158 }
Lee Thomason22aead12012-01-23 13:29:35 -08001159
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 // Skip white space before =
1161 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001162 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 return 0;
1164 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001165
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 ++p; // move up to opening quote
1167 p = XMLUtil::SkipWhiteSpace( p );
1168 if ( *p != '\"' && *p != '\'' ) {
1169 return 0;
1170 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001171
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 char endTag[2] = { *p, 0 };
1173 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001174
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001177}
1178
1179
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001180void XMLAttribute::SetName( const char* n )
1181{
Lee Thomason624d43f2012-10-12 10:58:48 -07001182 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001183}
1184
1185
Lee Thomason2fa81722012-11-09 12:37:46 -08001186XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( XMLUtil::ToInt( Value(), value )) {
1189 return XML_NO_ERROR;
1190 }
1191 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001192}
1193
1194
Lee Thomason2fa81722012-11-09 12:37:46 -08001195XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::ToUnsigned( Value(), value )) {
1198 return XML_NO_ERROR;
1199 }
1200 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201}
1202
1203
Lee Thomason2fa81722012-11-09 12:37:46 -08001204XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 if ( XMLUtil::ToBool( Value(), value )) {
1207 return XML_NO_ERROR;
1208 }
1209 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210}
1211
1212
Lee Thomason2fa81722012-11-09 12:37:46 -08001213XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( XMLUtil::ToFloat( Value(), value )) {
1216 return XML_NO_ERROR;
1217 }
1218 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001219}
1220
1221
Lee Thomason2fa81722012-11-09 12:37:46 -08001222XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( XMLUtil::ToDouble( Value(), value )) {
1225 return XML_NO_ERROR;
1226 }
1227 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001228}
1229
1230
1231void XMLAttribute::SetAttribute( const char* v )
1232{
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001234}
1235
1236
Lee Thomason1ff38e02012-02-14 18:18:16 -08001237void XMLAttribute::SetAttribute( int v )
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 char buf[BUF_SIZE];
1240 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001242}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001243
1244
1245void XMLAttribute::SetAttribute( unsigned v )
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 char buf[BUF_SIZE];
1248 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001249 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001250}
1251
1252
1253void XMLAttribute::SetAttribute( bool v )
1254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 char buf[BUF_SIZE];
1256 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001257 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001258}
1259
1260void XMLAttribute::SetAttribute( double v )
1261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 char buf[BUF_SIZE];
1263 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001265}
1266
1267void XMLAttribute::SetAttribute( float v )
1268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 char buf[BUF_SIZE];
1270 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001271 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272}
1273
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001274
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001275// --------- XMLElement ---------- //
1276XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001277 _closingType( 0 ),
1278 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001279{
1280}
1281
1282
1283XMLElement::~XMLElement()
1284{
Lee Thomason624d43f2012-10-12 10:58:48 -07001285 while( _rootAttribute ) {
1286 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001287 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001288 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001290}
1291
1292
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001293const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1294{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001295 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1297 return a;
1298 }
1299 }
1300 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001301}
1302
1303
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001304const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 const XMLAttribute* a = FindAttribute( name );
1307 if ( !a ) {
1308 return 0;
1309 }
1310 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1311 return a->Value();
1312 }
1313 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001314}
1315
1316
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001317const char* XMLElement::GetText() const
1318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001320 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 }
1322 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001323}
1324
1325
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001326void XMLElement::SetText( const char* inText )
1327{
Uli Kusterer869bb592014-01-21 01:36:16 +01001328 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001329 FirstChild()->SetValue( inText );
1330 else {
1331 XMLText* theText = GetDocument()->NewText( inText );
1332 InsertFirstChild( theText );
1333 }
1334}
1335
Lee Thomason5bb2d802014-01-24 10:42:57 -08001336
1337void XMLElement::SetText( int v )
1338{
1339 char buf[BUF_SIZE];
1340 XMLUtil::ToStr( v, buf, BUF_SIZE );
1341 SetText( buf );
1342}
1343
1344
1345void XMLElement::SetText( unsigned v )
1346{
1347 char buf[BUF_SIZE];
1348 XMLUtil::ToStr( v, buf, BUF_SIZE );
1349 SetText( buf );
1350}
1351
1352
1353void XMLElement::SetText( bool v )
1354{
1355 char buf[BUF_SIZE];
1356 XMLUtil::ToStr( v, buf, BUF_SIZE );
1357 SetText( buf );
1358}
1359
1360
1361void XMLElement::SetText( float v )
1362{
1363 char buf[BUF_SIZE];
1364 XMLUtil::ToStr( v, buf, BUF_SIZE );
1365 SetText( buf );
1366}
1367
1368
1369void XMLElement::SetText( double v )
1370{
1371 char buf[BUF_SIZE];
1372 XMLUtil::ToStr( v, buf, BUF_SIZE );
1373 SetText( buf );
1374}
1375
1376
MortenMacFly4ee49f12013-01-14 20:03:14 +01001377XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001380 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001381 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 return XML_SUCCESS;
1383 }
1384 return XML_CAN_NOT_CONVERT_TEXT;
1385 }
1386 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001387}
1388
1389
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001393 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001394 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 return XML_SUCCESS;
1396 }
1397 return XML_CAN_NOT_CONVERT_TEXT;
1398 }
1399 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001400}
1401
1402
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001406 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 return XML_SUCCESS;
1409 }
1410 return XML_CAN_NOT_CONVERT_TEXT;
1411 }
1412 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001413}
1414
1415
MortenMacFly4ee49f12013-01-14 20:03:14 +01001416XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001419 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001420 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 return XML_SUCCESS;
1422 }
1423 return XML_CAN_NOT_CONVERT_TEXT;
1424 }
1425 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001426}
1427
1428
MortenMacFly4ee49f12013-01-14 20:03:14 +01001429XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001432 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001433 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 return XML_SUCCESS;
1435 }
1436 return XML_CAN_NOT_CONVERT_TEXT;
1437 }
1438 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001439}
1440
1441
1442
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001443XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 XMLAttribute* last = 0;
1446 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1451 break;
1452 }
1453 }
1454 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001455 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1457 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001465 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 }
1467 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001468}
1469
1470
U-Stream\Leeae25a442012-02-17 17:48:16 -08001471void XMLElement::DeleteAttribute( const char* name )
1472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1476 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 }
1479 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001482 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 break;
1484 }
1485 prev = a;
1486 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001487}
1488
1489
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001490char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 const char* start = p;
1493 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001494
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 // Read the attributes.
1496 while( p ) {
1497 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001498 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 return 0;
1501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001502
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001504 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001505 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1507 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001508 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001509
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001512 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
1516 // There is a minor bug here: if the attribute in the source xml
1517 // document is duplicated, it will not be detected and the
1518 // attribute will be doubly added. However, tracking the 'prevAttribute'
1519 // avoids re-scanning the attribute list. Preferring performance for
1520 // now, may reconsider in the future.
1521 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 }
1524 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001525 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 }
1527 prevAttribute = attrib;
1528 }
1529 // end of the tag
1530 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 return p+2; // done; sealed element.
1533 }
1534 // end of the tag
1535 else if ( *p == '>' ) {
1536 ++p;
1537 break;
1538 }
1539 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return 0;
1542 }
1543 }
1544 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001545}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001546
Dmitry-Mee3225b12014-09-03 11:03:11 +04001547void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1548{
1549 if ( attribute == 0 ) {
1550 return;
1551 }
1552 MemPool* pool = attribute->_memPool;
1553 attribute->~XMLAttribute();
1554 pool->Free( attribute );
1555}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001556
Lee Thomason67d61312012-01-24 16:01:51 -08001557//
1558// <ele></ele>
1559// <ele>foo<b>bar</b></ele>
1560//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001561char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001562{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 // Read the element name.
1564 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001565
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 // The closing element is the </element> form. It is
1567 // parsed just like a regular element then deleted from
1568 // the DOM.
1569 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 ++p;
1572 }
Lee Thomason67d61312012-01-24 16:01:51 -08001573
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 p = _value.ParseName( p );
1575 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 return 0;
1577 }
Lee Thomason67d61312012-01-24 16:01:51 -08001578
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001580 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 return p;
1582 }
Lee Thomason67d61312012-01-24 16:01:51 -08001583
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 p = XMLNode::ParseDeep( p, strPair );
1585 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001586}
1587
1588
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001589
1590XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001593 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 }
1595 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1596 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1597 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1598 }
1599 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001600}
1601
1602
1603bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1604{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001605 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 const XMLElement* other = compare->ToElement();
1607 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001608
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 const XMLAttribute* a=FirstAttribute();
1610 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001611
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001612 while ( a && b ) {
1613 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1614 return false;
1615 }
1616 a = a->Next();
1617 b = b->Next();
1618 }
1619 if ( a || b ) {
1620 // different count
1621 return false;
1622 }
1623 return true;
1624 }
1625 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001626}
1627
1628
Lee Thomason751da522012-02-10 08:50:51 -08001629bool XMLElement::Accept( XMLVisitor* visitor ) const
1630{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001631 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1634 if ( !node->Accept( visitor ) ) {
1635 break;
1636 }
1637 }
1638 }
1639 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001640}
Lee Thomason56bdd022012-02-09 18:16:58 -08001641
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001642
Lee Thomason3f57d272012-01-11 15:30:03 -08001643// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001644
1645// Warning: List must match 'enum XMLError'
1646const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1647 "XML_SUCCESS",
1648 "XML_NO_ATTRIBUTE",
1649 "XML_WRONG_ATTRIBUTE_TYPE",
1650 "XML_ERROR_FILE_NOT_FOUND",
1651 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1652 "XML_ERROR_FILE_READ_ERROR",
1653 "XML_ERROR_ELEMENT_MISMATCH",
1654 "XML_ERROR_PARSING_ELEMENT",
1655 "XML_ERROR_PARSING_ATTRIBUTE",
1656 "XML_ERROR_IDENTIFYING_TAG",
1657 "XML_ERROR_PARSING_TEXT",
1658 "XML_ERROR_PARSING_CDATA",
1659 "XML_ERROR_PARSING_COMMENT",
1660 "XML_ERROR_PARSING_DECLARATION",
1661 "XML_ERROR_PARSING_UNKNOWN",
1662 "XML_ERROR_EMPTY_DOCUMENT",
1663 "XML_ERROR_MISMATCHED_ELEMENT",
1664 "XML_ERROR_PARSING",
1665 "XML_CAN_NOT_CONVERT_TEXT",
1666 "XML_NO_TEXT_NODE"
1667};
1668
1669
Lee Thomason624d43f2012-10-12 10:58:48 -07001670XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 _writeBOM( false ),
1673 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001674 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 _whitespace( whitespace ),
1676 _errorStr1( 0 ),
1677 _errorStr2( 0 ),
1678 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001679{
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001681}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001682
1683
Lee Thomason3f57d272012-01-11 15:30:03 -08001684XMLDocument::~XMLDocument()
1685{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001686 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001687}
1688
1689
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001690void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001691{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001692 DeleteChildren();
1693
Dmitry-Meab37df82014-11-28 12:08:36 +03001694#ifdef DEBUG
1695 const bool hadError = Error();
1696#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 _errorID = XML_NO_ERROR;
1698 _errorStr1 = 0;
1699 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001700
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 delete [] _charBuffer;
1702 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001703
1704#if 0
1705 _textPool.Trace( "text" );
1706 _elementPool.Trace( "element" );
1707 _commentPool.Trace( "comment" );
1708 _attributePool.Trace( "attribute" );
1709#endif
1710
1711#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001712 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001713 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1714 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1715 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1716 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1717 }
1718#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001719}
1720
Lee Thomason3f57d272012-01-11 15:30:03 -08001721
Lee Thomason2c85a712012-01-31 08:24:24 -08001722XMLElement* XMLDocument::NewElement( const char* name )
1723{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001724 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1726 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 ele->SetName( name );
1728 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001729}
1730
1731
Lee Thomason1ff38e02012-02-14 18:18:16 -08001732XMLComment* XMLDocument::NewComment( const char* str )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1736 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 comment->SetValue( str );
1738 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001739}
1740
1741
1742XMLText* XMLDocument::NewText( const char* str )
1743{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001744 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1746 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 text->SetValue( str );
1748 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001749}
1750
1751
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001752XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1753{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001754 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1756 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1758 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001759}
1760
1761
1762XMLUnknown* XMLDocument::NewUnknown( const char* str )
1763{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001764 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1766 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 unk->SetValue( str );
1768 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001769}
1770
Dmitry-Me01578db2014-08-19 10:18:48 +04001771static FILE* callfopen( const char* filepath, const char* mode )
1772{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001773 TIXMLASSERT( filepath );
1774 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001775#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1776 FILE* fp = 0;
1777 errno_t err = fopen_s( &fp, filepath, mode );
1778 if ( err ) {
1779 return 0;
1780 }
1781#else
1782 FILE* fp = fopen( filepath, mode );
1783#endif
1784 return fp;
1785}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001786
1787void XMLDocument::DeleteNode( XMLNode* node ) {
1788 TIXMLASSERT( node );
1789 TIXMLASSERT(node->_document == this );
1790 if (node->_parent) {
1791 node->_parent->DeleteChild( node );
1792 }
1793 else {
1794 // Isn't in the tree.
1795 // Use the parent delete.
1796 // Also, we need to mark it tracked: we 'know'
1797 // it was never used.
1798 node->_memPool->SetTracked();
1799 // Call the static XMLNode version:
1800 XMLNode::DeleteNode(node);
1801 }
1802}
1803
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001804
Lee Thomason2fa81722012-11-09 12:37:46 -08001805XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001806{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001807 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001808 FILE* fp = callfopen( filename, "rb" );
1809 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 }
1813 LoadFile( fp );
1814 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001816}
1817
1818
Lee Thomason2fa81722012-11-09 12:37:46 -08001819XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001820{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001821 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001822
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001823 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001824 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001825 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1826 return _errorID;
1827 }
1828
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001830 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001832 if ( filelength == -1L ) {
1833 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1834 return _errorID;
1835 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001836
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001837 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001839 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001842
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _charBuffer = new char[size+1];
1844 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( read != size ) {
1846 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001849
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001851
Dmitry-Me97476b72015-01-01 16:15:57 +03001852 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001854}
1855
1856
Lee Thomason2fa81722012-11-09 12:37:46 -08001857XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001858{
Dmitry-Me01578db2014-08-19 10:18:48 +04001859 FILE* fp = callfopen( filename, "w" );
1860 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 }
1864 SaveFile(fp, compact);
1865 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001867}
1868
1869
Lee Thomason2fa81722012-11-09 12:37:46 -08001870XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001871{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 XMLPrinter stream( fp, compact );
1873 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001875}
1876
Lee Thomason1ff38e02012-02-14 18:18:16 -08001877
Lee Thomason2fa81722012-11-09 12:37:46 -08001878XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001879{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001880 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001881
Lee Thomason82d32002014-02-21 22:47:18 -08001882 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 }
1886 if ( len == (size_t)(-1) ) {
1887 len = strlen( p );
1888 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001889 _charBuffer = new char[ len+1 ];
1890 memcpy( _charBuffer, p, len );
1891 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001892
Dmitry-Me97476b72015-01-01 16:15:57 +03001893 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001894 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001895 // clean up now essentially dangling memory.
1896 // and the parse fail can put objects in the
1897 // pools that are dead and inaccessible.
1898 DeleteChildren();
1899 _elementPool.Clear();
1900 _attributePool.Clear();
1901 _textPool.Clear();
1902 _commentPool.Clear();
1903 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001905}
1906
1907
PKEuS1c5f99e2013-07-06 11:28:39 +02001908void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001909{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 XMLPrinter stdStreamer( stdout );
1911 if ( !streamer ) {
1912 streamer = &stdStreamer;
1913 }
1914 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001915}
1916
1917
Lee Thomason2fa81722012-11-09 12:37:46 -08001918void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001919{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001920 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 _errorID = error;
1922 _errorStr1 = str1;
1923 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001924}
1925
Lee Thomason331596e2014-09-11 14:56:43 -07001926const char* XMLDocument::ErrorName() const
1927{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001928 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001929 return _errorNames[_errorID];
1930}
Lee Thomason5cae8972012-01-24 18:03:07 -08001931
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001932void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001933{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001934 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 static const int LEN = 20;
1936 char buf1[LEN] = { 0 };
1937 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001938
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 if ( _errorStr1 ) {
1940 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 if ( _errorStr2 ) {
1943 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001945
Lee Thomason331596e2014-09-11 14:56:43 -07001946 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1947 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001949}
1950
Dmitry-Me97476b72015-01-01 16:15:57 +03001951void XMLDocument::Parse()
1952{
1953 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1954 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001955 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001956 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001957 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001958 if ( !*p ) {
1959 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1960 return;
1961 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08001962 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03001963}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001964
PKEuS1bfb9542013-08-04 13:51:17 +02001965XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 _elementJustOpened( false ),
1967 _firstElement( true ),
1968 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001969 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _textDepth( -1 ),
1971 _processEntities( true ),
1972 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 _entityFlag[i] = false;
1976 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 }
1978 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001979 const char entityValue = entities[i].value;
1980 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1981 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001982 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001983 _restrictedEntityFlag[(unsigned char)'&'] = true;
1984 _restrictedEntityFlag[(unsigned char)'<'] = true;
1985 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001986 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001987}
1988
1989
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001990void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001991{
1992 va_list va;
1993 va_start( va, format );
1994
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 if ( _fp ) {
1996 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 }
1998 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001999#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002000 #if defined(WINCE)
2001 int len = 512;
2002 do {
2003 len = len*2;
2004 char* str = new char[len]();
2005 len = _vsnprintf(str, len, format, va);
2006 delete[] str;
2007 }while (len < 0);
2008 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002009 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002010 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011#else
2012 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002013#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 // Close out and re-start the va-args
2015 va_end( va );
2016 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002017 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002018 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2019#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002020 #if defined(WINCE)
2021 _vsnprintf( p, len+1, format, va );
2022 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002023 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002024 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002025#else
2026 vsnprintf( p, len+1, format, va );
2027#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002029 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002030}
2031
2032
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002033void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 for( int i=0; i<depth; ++i ) {
2036 Print( " " );
2037 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002038}
2039
2040
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002041void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 // Look for runs of bytes between entities to print.
2044 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002045
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002047 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 while ( *q ) {
2049 // Remember, char is sometimes signed. (How many times has that bitten me?)
2050 if ( *q > 0 && *q < ENTITY_RANGE ) {
2051 // Check for entities. If one is found, flush
2052 // the stream up until the entity, write the
2053 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002054 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 while ( p < q ) {
2056 Print( "%c", *p );
2057 ++p;
2058 }
2059 for( int i=0; i<NUM_ENTITIES; ++i ) {
2060 if ( entities[i].value == *q ) {
2061 Print( "&%s;", entities[i].pattern );
2062 break;
2063 }
2064 }
2065 ++p;
2066 }
2067 }
2068 ++q;
2069 }
2070 }
2071 // Flush the remaining string. This will be the entire
2072 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 Print( "%s", p );
2075 }
Lee Thomason857b8682012-01-25 17:50:25 -08002076}
2077
U-Stream\Leeae25a442012-02-17 17:48:16 -08002078
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002079void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002082 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 -07002083 Print( "%s", bom );
2084 }
2085 if ( writeDec ) {
2086 PushDeclaration( "xml version=\"1.0\"" );
2087 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002088}
2089
2090
Uli Kusterer593a33d2014-02-01 12:48:51 +01002091void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002092{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002093 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002095
Uli Kusterer593a33d2014-02-01 12:48:51 +01002096 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002098 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002099 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002100 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002102
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002104 _elementJustOpened = true;
2105 _firstElement = false;
2106 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002107}
2108
2109
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002110void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002111{
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 Print( " %s=\"", name );
2114 PrintString( value, false );
2115 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002116}
2117
2118
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002119void XMLPrinter::PushAttribute( const char* name, int v )
2120{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 char buf[BUF_SIZE];
2122 XMLUtil::ToStr( v, buf, BUF_SIZE );
2123 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002124}
2125
2126
2127void XMLPrinter::PushAttribute( const char* name, unsigned v )
2128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 char buf[BUF_SIZE];
2130 XMLUtil::ToStr( v, buf, BUF_SIZE );
2131 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002132}
2133
2134
2135void XMLPrinter::PushAttribute( const char* name, bool v )
2136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 char buf[BUF_SIZE];
2138 XMLUtil::ToStr( v, buf, BUF_SIZE );
2139 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002140}
2141
2142
2143void XMLPrinter::PushAttribute( const char* name, double v )
2144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 char buf[BUF_SIZE];
2146 XMLUtil::ToStr( v, buf, BUF_SIZE );
2147 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002148}
2149
2150
Uli Kustererca412e82014-02-01 13:35:05 +01002151void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002152{
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 --_depth;
2154 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002155
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( "/>" );
2158 }
2159 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002160 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 }
2164 Print( "</%s>", name );
2165 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002166
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 if ( _textDepth == _depth ) {
2168 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 }
Uli Kustererca412e82014-02-01 13:35:05 +01002170 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 Print( "\n" );
2172 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002174}
2175
2176
Dmitry-Mea092bc12014-12-23 17:57:05 +03002177void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002178{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002179 if ( !_elementJustOpened ) {
2180 return;
2181 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002184}
2185
2186
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002187void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002188{
Lee Thomason624d43f2012-10-12 10:58:48 -07002189 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002190
Dmitry-Mea092bc12014-12-23 17:57:05 +03002191 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 if ( cdata ) {
2193 Print( "<![CDATA[" );
2194 Print( "%s", text );
2195 Print( "]]>" );
2196 }
2197 else {
2198 PrintString( text, true );
2199 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002200}
2201
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002202void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002203{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 char buf[BUF_SIZE];
2205 XMLUtil::ToStr( value, buf, BUF_SIZE );
2206 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002207}
2208
2209
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002210void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 char buf[BUF_SIZE];
2213 XMLUtil::ToStr( value, buf, BUF_SIZE );
2214 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002215}
2216
2217
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002218void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 char buf[BUF_SIZE];
2221 XMLUtil::ToStr( value, buf, BUF_SIZE );
2222 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002223}
2224
2225
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002226void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 char buf[BUF_SIZE];
2229 XMLUtil::ToStr( value, buf, BUF_SIZE );
2230 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002231}
2232
2233
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002234void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 char buf[BUF_SIZE];
2237 XMLUtil::ToStr( value, buf, BUF_SIZE );
2238 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002239}
2240
Lee Thomason5cae8972012-01-24 18:03:07 -08002241
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002242void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002243{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002244 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002251}
Lee Thomason751da522012-02-10 08:50:51 -08002252
2253
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002254void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002255{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002256 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002263}
2264
2265
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002266void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002267{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002268 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002273 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002275}
2276
2277
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002278bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002279{
Lee Thomason624d43f2012-10-12 10:58:48 -07002280 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 if ( doc.HasBOM() ) {
2282 PushHeader( true, false );
2283 }
2284 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002289{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002290 const XMLElement* parentElem = element.Parent()->ToElement();
2291 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2292 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 while ( attribute ) {
2294 PushAttribute( attribute->Name(), attribute->Value() );
2295 attribute = attribute->Next();
2296 }
2297 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002298}
2299
2300
Uli Kustererca412e82014-02-01 13:35:05 +01002301bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002302{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002303 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002305}
2306
2307
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002308bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 PushText( text.Value(), text.CData() );
2311 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002312}
2313
2314
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002315bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 PushComment( comment.Value() );
2318 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002319}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002320
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002321bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002322{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 PushDeclaration( declaration.Value() );
2324 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002325}
2326
2327
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002328bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002329{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002330 PushUnknown( unknown.Value() );
2331 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002332}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002333
Lee Thomason685b8952012-11-12 13:00:06 -08002334} // namespace tinyxml2
2335