blob: ad854cbcd39e763b52f1e07ee7f9e819c7d3275e [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 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
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
Lee Thomason120b3a62012-10-12 10:06:59 -0700165 if ( _start && *_start ) {
166 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{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 *bom = false;
281 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
282 // Check for BOM:
283 if ( *(pu+0) == TIXML_UTF_LEAD_0
284 && *(pu+1) == TIXML_UTF_LEAD_1
285 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
286 *bom = true;
287 p += 3;
288 }
289 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if (input < 0x80) {
300 *length = 1;
301 }
302 else if ( input < 0x800 ) {
303 *length = 2;
304 }
305 else if ( input < 0x10000 ) {
306 *length = 3;
307 }
308 else if ( input < 0x200000 ) {
309 *length = 4;
310 }
311 else {
312 *length = 0; // This code won't covert this correctly anyway.
313 return;
314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800317
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 // Scary scary fall throughs.
319 switch (*length) {
320 case 4:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 3:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 2:
329 --output;
330 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
331 input >>= 6;
332 case 1:
333 --output;
334 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100335 default:
336 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800338}
339
340
341const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 // Presume an entity, and pull it out.
344 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 if ( *(p+1) == '#' && *(p+2) ) {
347 unsigned long ucs = 0;
348 ptrdiff_t delta = 0;
349 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( *(p+2) == 'x' ) {
352 // Hexadecimal.
353 if ( !*(p+3) ) {
354 return 0;
355 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 const char* q = p+3;
358 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( !q || !*q ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 delta = q-p;
365 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 while ( *q != 'x' ) {
368 if ( *q >= '0' && *q <= '9' ) {
369 ucs += mult * (*q - '0');
370 }
371 else if ( *q >= 'a' && *q <= 'f' ) {
372 ucs += mult * (*q - 'a' + 10);
373 }
374 else if ( *q >= 'A' && *q <= 'F' ) {
375 ucs += mult * (*q - 'A' + 10 );
376 }
377 else {
378 return 0;
379 }
380 mult *= 16;
381 --q;
382 }
383 }
384 else {
385 // Decimal.
386 if ( !*(p+2) ) {
387 return 0;
388 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 const char* q = p+2;
391 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 if ( !q || !*q ) {
394 return 0;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 delta = q-p;
398 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 while ( *q != '#' ) {
401 if ( *q >= '0' && *q <= '9' ) {
402 ucs += mult * (*q - '0');
403 }
404 else {
405 return 0;
406 }
407 mult *= 10;
408 --q;
409 }
410 }
411 // convert the UCS to UTF-8
412 ConvertUTF32ToUTF8( ucs, value, length );
413 return p + delta + 1;
414 }
415 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800417
418
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700419void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800436/*
437 ToStr() of a number is a very tricky topic.
438 https://github.com/leethomason/tinyxml2/issues/106
439*/
Lee Thomason21be8822012-07-15 17:27:22 -0700440void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
441{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452bool XMLUtil::ToInt( const char* str, int* value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
463 return true;
464 }
465 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468bool XMLUtil::ToBool( const char* str, bool* value )
469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 int ival = 0;
471 if ( ToInt( str, &ival )) {
472 *value = (ival==0) ? false : true;
473 return true;
474 }
475 if ( StringEqual( str, "true" ) ) {
476 *value = true;
477 return true;
478 }
479 else if ( StringEqual( str, "false" ) ) {
480 *value = false;
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486
487bool XMLUtil::ToFloat( const char* str, float* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495bool XMLUtil::ToDouble( const char* str, double* value )
496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498 return true;
499 }
500 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700501}
502
503
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700504char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400506 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 p = XMLUtil::SkipWhiteSpace( p );
508 if( !p || !*p ) {
509 return p;
510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800513 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const char* xmlHeader = { "<?" };
515 static const char* commentHeader = { "<!--" };
516 static const char* dtdHeader = { "<!" };
517 static const char* cdataHeader = { "<![CDATA[" };
518 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const int xmlHeaderLen = 2;
521 static const int commentHeaderLen = 4;
522 static const int dtdHeaderLen = 2;
523 static const int cdataHeaderLen = 9;
524 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning ( push )
528#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
531 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800533#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800534#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400535 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300537 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += xmlHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300543 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_commentPool.Alloc()) XMLComment( this );
545 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += commentHeaderLen;
547 }
548 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300549 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += cdataHeaderLen;
554 text->SetCData( true );
555 }
556 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300557 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
559 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p += dtdHeaderLen;
561 }
562 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300563 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_elementPool.Alloc()) XMLElement( this );
565 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p += elementHeaderLen;
567 }
568 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300569 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 returnNode = new (_textPool.Alloc()) XMLText( this );
571 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 p = start; // Back it up, all the text counts.
573 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 *node = returnNode;
576 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577}
578
579
Lee Thomason751da522012-02-10 08:50:51 -0800580bool XMLDocument::Accept( XMLVisitor* visitor ) const
581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 if ( visitor->VisitEnter( *this ) ) {
583 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
584 if ( !node->Accept( visitor ) ) {
585 break;
586 }
587 }
588 }
589 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800590}
Lee Thomason56bdd022012-02-09 18:16:58 -0800591
592
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800593// --------- XMLNode ----------- //
594
595XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700596 _document( doc ),
597 _parent( 0 ),
598 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200599 _prev( 0 ), _next( 0 ),
600 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800602}
603
604
605XMLNode::~XMLNode()
606{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 if ( _parent ) {
609 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611}
612
Michael Daumling21626882013-10-22 17:03:37 +0200613const char* XMLNode::Value() const
614{
615 return _value.GetStr();
616}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800617
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800618void XMLNode::SetValue( const char* str, bool staticMem )
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
623 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800626}
627
628
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800629void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800630{
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300632 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635
Dmitry-Mee3225b12014-09-03 11:03:11 +0400636 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800639}
640
641
642void XMLNode::Unlink( XMLNode* child )
643{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300664 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400666 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800667}
668
669
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
671{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300672 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300673 if ( addThis->_document != _document ) {
674 TIXMLASSERT( false );
675 return 0;
676 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Michael Daumlinged523282013-10-23 07:47:29 +0200678 if (addThis->_parent)
679 addThis->_parent->Unlink( addThis );
680 else
681 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 if ( _lastChild ) {
684 TIXMLASSERT( _firstChild );
685 TIXMLASSERT( _lastChild->_next == 0 );
686 _lastChild->_next = addThis;
687 addThis->_prev = _lastChild;
688 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
692 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 TIXMLASSERT( _firstChild == 0 );
694 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_prev = 0;
697 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701}
702
703
Lee Thomason1ff38e02012-02-14 18:18:16 -0800704XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
705{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300706 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300707 if ( addThis->_document != _document ) {
708 TIXMLASSERT( false );
709 return 0;
710 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700711
Michael Daumlinged523282013-10-23 07:47:29 +0200712 if (addThis->_parent)
713 addThis->_parent->Unlink( addThis );
714 else
715 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 if ( _firstChild ) {
718 TIXMLASSERT( _lastChild );
719 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 _firstChild->_prev = addThis;
722 addThis->_next = _firstChild;
723 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
727 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 TIXMLASSERT( _lastChild == 0 );
729 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_prev = 0;
732 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400735 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800736}
737
738
739XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
740{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 TIXMLASSERT( addThis );
742 if ( addThis->_document != _document ) {
743 TIXMLASSERT( false );
744 return 0;
745 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Dmitry-Meabb2d042014-12-09 12:59:31 +0300747 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700748
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300750 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 return 0;
752 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 // The last node or the only node.
756 return InsertEndChild( addThis );
757 }
Michael Daumlinged523282013-10-23 07:47:29 +0200758 if (addThis->_parent)
759 addThis->_parent->Unlink( addThis );
760 else
761 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 addThis->_prev = afterThis;
763 addThis->_next = afterThis->_next;
764 afterThis->_next->_prev = addThis;
765 afterThis->_next = addThis;
766 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800768}
769
770
771
772
Lee Thomason56bdd022012-02-09 18:16:58 -0800773const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800774{
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 XMLElement* element = node->ToElement();
777 if ( element ) {
778 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
779 return element;
780 }
781 }
782 }
783 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800784}
785
786
Lee Thomason56bdd022012-02-09 18:16:58 -0800787const XMLElement* XMLNode::LastChildElement( const char* value ) const
788{
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
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 Thomason56bdd022012-02-09 18:16:58 -0800798}
799
800
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800801const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
802{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400803 for( XMLNode* node=this->_next; node; node = node->_next ) {
804 const XMLElement* element = node->ToElement();
805 if ( element
806 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
807 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
809 }
810 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800811}
812
813
814const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
815{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400816 for( XMLNode* node=_prev; node; node = node->_prev ) {
817 const XMLElement* element = node->ToElement();
818 if ( element
819 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
820 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
822 }
823 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800824}
825
826
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800827char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800828{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 // This is a recursive method, but thinking about it "at the current level"
830 // it is a pretty simple flat list:
831 // <foo/>
832 // <!-- comment -->
833 //
834 // With a special case:
835 // <foo>
836 // </foo>
837 // <!-- comment -->
838 //
839 // Where the closing element (/foo) *must* be the next thing after the opening
840 // element, and the names must match. BUT the tricky bit is that the closing
841 // element will be read by the child.
842 //
843 // 'endTag' is the end tag for this node, it is returned by a call to a child.
844 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 while( p && *p ) {
847 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 if ( p == 0 || node == 0 ) {
851 break;
852 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 StrPair endTag;
855 p = node->ParseDeep( p, &endTag );
856 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400857 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 if ( !_document->Error() ) {
860 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 }
862 break;
863 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800864
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400865 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400867 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800869 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800871 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400872 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 return p;
874 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800875
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 // Handle an end tag returned to this level.
877 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400879 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400884 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
886 else if ( !endTag.Empty() ) {
887 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400891 if ( mismatch ) {
892 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
893 p = 0;
894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400897 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 node = 0;
899 }
900 if ( node ) {
901 this->InsertEndChild( node );
902 }
903 }
904 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800905}
906
Dmitry-Mee3225b12014-09-03 11:03:11 +0400907void XMLNode::DeleteNode( XMLNode* node )
908{
909 if ( node == 0 ) {
910 return;
911 }
912 MemPool* pool = node->_memPool;
913 node->~XMLNode();
914 pool->Free( node );
915}
916
Lee Thomason5492a1c2012-01-23 15:32:10 -0800917// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800918char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 const char* start = p;
921 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 }
926 return p;
927 }
928 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
930 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 flags |= StrPair::COLLAPSE_WHITESPACE;
932 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700936 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 }
938 if ( p && *p ) {
939 return p-1;
940 }
941 }
942 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800943}
944
945
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700949 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 }
951 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
952 text->SetCData( this->CData() );
953 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954}
955
956
957bool XMLText::ShallowEqual( const XMLNode* compare ) const
958{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400959 const XMLText* text = compare->ToText();
960 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961}
962
963
Lee Thomason56bdd022012-02-09 18:16:58 -0800964bool XMLText::Accept( XMLVisitor* visitor ) const
965{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300966 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800968}
969
970
Lee Thomason3f57d272012-01-11 15:30:03 -0800971// --------- XMLComment ---------- //
972
Lee Thomasone4422302012-01-20 17:59:50 -0800973XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800974{
975}
976
977
Lee Thomasonce0763e2012-01-11 15:43:54 -0800978XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
Lee Thomason3f57d272012-01-11 15:30:03 -0800980}
981
982
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800983char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 // Comment parses as text.
986 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700987 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 }
991 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800992}
993
994
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1001 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
1005bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1006{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001007 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLComment* comment = compare->ToComment();
1009 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
Lee Thomason751da522012-02-10 08:50:51 -08001013bool XMLComment::Accept( XMLVisitor* visitor ) const
1014{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001015 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001017}
Lee Thomason56bdd022012-02-09 18:16:58 -08001018
1019
Lee Thomason50f97b22012-02-11 16:33:40 -08001020// --------- XMLDeclaration ---------- //
1021
1022XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1023{
1024}
1025
1026
1027XMLDeclaration::~XMLDeclaration()
1028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001030}
1031
1032
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 // Declaration parses as text.
1036 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001042}
1043
1044
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 }
1050 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1051 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1056{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001057 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001058 const XMLDeclaration* declaration = compare->ToDeclaration();
1059 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001060}
1061
1062
1063
Lee Thomason50f97b22012-02-11 16:33:40 -08001064bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1065{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001066 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
1070// --------- XMLUnknown ---------- //
1071
1072XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1073{
1074}
1075
1076
1077XMLUnknown::~XMLUnknown()
1078{
1079}
1080
1081
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001082char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Unknown parses as text.
1085 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001086
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001092}
1093
1094
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001098 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 }
1100 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1101 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
1105bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001108 const XMLUnknown* unknown = compare->ToUnknown();
1109 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110}
1111
1112
Lee Thomason50f97b22012-02-11 16:33:40 -08001113bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1114{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001115 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001117}
1118
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001119// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001120
1121const char* XMLAttribute::Name() const
1122{
1123 return _name.GetStr();
1124}
1125
1126const char* XMLAttribute::Value() const
1127{
1128 return _value.GetStr();
1129}
1130
Lee Thomason6f381b72012-03-02 12:59:39 -08001131char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001134 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !p || !*p ) {
1136 return 0;
1137 }
Lee Thomason22aead12012-01-23 13:29:35 -08001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 // Skip white space before =
1140 p = XMLUtil::SkipWhiteSpace( p );
1141 if ( !p || *p != '=' ) {
1142 return 0;
1143 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001144
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 ++p; // move up to opening quote
1146 p = XMLUtil::SkipWhiteSpace( p );
1147 if ( *p != '\"' && *p != '\'' ) {
1148 return 0;
1149 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001150
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 char endTag[2] = { *p, 0 };
1152 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001153
Lee Thomason624d43f2012-10-12 10:58:48 -07001154 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001156}
1157
1158
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001159void XMLAttribute::SetName( const char* n )
1160{
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001162}
1163
1164
Lee Thomason2fa81722012-11-09 12:37:46 -08001165XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 if ( XMLUtil::ToInt( Value(), value )) {
1168 return XML_NO_ERROR;
1169 }
1170 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171}
1172
1173
Lee Thomason2fa81722012-11-09 12:37:46 -08001174XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( XMLUtil::ToUnsigned( Value(), value )) {
1177 return XML_NO_ERROR;
1178 }
1179 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
1181
1182
Lee Thomason2fa81722012-11-09 12:37:46 -08001183XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::ToBool( Value(), value )) {
1186 return XML_NO_ERROR;
1187 }
1188 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189}
1190
1191
Lee Thomason2fa81722012-11-09 12:37:46 -08001192XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 if ( XMLUtil::ToFloat( Value(), value )) {
1195 return XML_NO_ERROR;
1196 }
1197 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001198}
1199
1200
Lee Thomason2fa81722012-11-09 12:37:46 -08001201XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( XMLUtil::ToDouble( Value(), value )) {
1204 return XML_NO_ERROR;
1205 }
1206 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
1210void XMLAttribute::SetAttribute( const char* v )
1211{
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
1214
1215
Lee Thomason1ff38e02012-02-14 18:18:16 -08001216void XMLAttribute::SetAttribute( int v )
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 char buf[BUF_SIZE];
1219 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001221}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001222
1223
1224void XMLAttribute::SetAttribute( unsigned v )
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 char buf[BUF_SIZE];
1227 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231
1232void XMLAttribute::SetAttribute( bool v )
1233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 char buf[BUF_SIZE];
1235 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001237}
1238
1239void XMLAttribute::SetAttribute( double v )
1240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 char buf[BUF_SIZE];
1242 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001244}
1245
1246void XMLAttribute::SetAttribute( float v )
1247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 char buf[BUF_SIZE];
1249 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001251}
1252
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001253
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001254// --------- XMLElement ---------- //
1255XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 _closingType( 0 ),
1257 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001258{
1259}
1260
1261
1262XMLElement::~XMLElement()
1263{
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 while( _rootAttribute ) {
1265 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001266 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269}
1270
1271
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1273{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001274 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1276 return a;
1277 }
1278 }
1279 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001280}
1281
1282
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001283const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 const XMLAttribute* a = FindAttribute( name );
1286 if ( !a ) {
1287 return 0;
1288 }
1289 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1290 return a->Value();
1291 }
1292 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001293}
1294
1295
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296const char* XMLElement::GetText() const
1297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001299 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 }
1301 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001302}
1303
1304
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001305void XMLElement::SetText( const char* inText )
1306{
Uli Kusterer869bb592014-01-21 01:36:16 +01001307 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001308 FirstChild()->SetValue( inText );
1309 else {
1310 XMLText* theText = GetDocument()->NewText( inText );
1311 InsertFirstChild( theText );
1312 }
1313}
1314
Lee Thomason5bb2d802014-01-24 10:42:57 -08001315
1316void XMLElement::SetText( int v )
1317{
1318 char buf[BUF_SIZE];
1319 XMLUtil::ToStr( v, buf, BUF_SIZE );
1320 SetText( buf );
1321}
1322
1323
1324void XMLElement::SetText( unsigned v )
1325{
1326 char buf[BUF_SIZE];
1327 XMLUtil::ToStr( v, buf, BUF_SIZE );
1328 SetText( buf );
1329}
1330
1331
1332void XMLElement::SetText( bool v )
1333{
1334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
1336 SetText( buf );
1337}
1338
1339
1340void XMLElement::SetText( float v )
1341{
1342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
1344 SetText( buf );
1345}
1346
1347
1348void XMLElement::SetText( double v )
1349{
1350 char buf[BUF_SIZE];
1351 XMLUtil::ToStr( v, buf, BUF_SIZE );
1352 SetText( buf );
1353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001359 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001372 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001385 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return XML_SUCCESS;
1388 }
1389 return XML_CAN_NOT_CONVERT_TEXT;
1390 }
1391 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001392}
1393
1394
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001398 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 return XML_SUCCESS;
1401 }
1402 return XML_CAN_NOT_CONVERT_TEXT;
1403 }
1404 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001405}
1406
1407
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001411 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001412 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 return XML_SUCCESS;
1414 }
1415 return XML_CAN_NOT_CONVERT_TEXT;
1416 }
1417 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001418}
1419
1420
1421
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001422XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 XMLAttribute* last = 0;
1425 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1430 break;
1431 }
1432 }
1433 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001434 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1436 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001441 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 }
1443 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001444 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 }
1446 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001447}
1448
1449
U-Stream\Leeae25a442012-02-17 17:48:16 -08001450void XMLElement::DeleteAttribute( const char* name )
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1455 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 }
1458 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001461 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 break;
1463 }
1464 prev = a;
1465 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001466}
1467
1468
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001469char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 const char* start = p;
1472 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001473
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 // Read the attributes.
1475 while( p ) {
1476 p = XMLUtil::SkipWhiteSpace( p );
1477 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return 0;
1480 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001483 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001484 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1486 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001487 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001488
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001491 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 return 0;
1494 }
1495 // There is a minor bug here: if the attribute in the source xml
1496 // document is duplicated, it will not be detected and the
1497 // attribute will be doubly added. However, tracking the 'prevAttribute'
1498 // avoids re-scanning the attribute list. Preferring performance for
1499 // now, may reconsider in the future.
1500 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 }
1503 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 }
1506 prevAttribute = attrib;
1507 }
1508 // end of the tag
1509 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return p+2; // done; sealed element.
1512 }
1513 // end of the tag
1514 else if ( *p == '>' ) {
1515 ++p;
1516 break;
1517 }
1518 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 return 0;
1521 }
1522 }
1523 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001524}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Dmitry-Mee3225b12014-09-03 11:03:11 +04001526void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1527{
1528 if ( attribute == 0 ) {
1529 return;
1530 }
1531 MemPool* pool = attribute->_memPool;
1532 attribute->~XMLAttribute();
1533 pool->Free( attribute );
1534}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001535
Lee Thomason67d61312012-01-24 16:01:51 -08001536//
1537// <ele></ele>
1538// <ele>foo<b>bar</b></ele>
1539//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001540char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // Read the element name.
1543 p = XMLUtil::SkipWhiteSpace( p );
1544 if ( !p ) {
1545 return 0;
1546 }
Lee Thomason67d61312012-01-24 16:01:51 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 // The closing element is the </element> form. It is
1549 // parsed just like a regular element then deleted from
1550 // the DOM.
1551 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 ++p;
1554 }
Lee Thomason67d61312012-01-24 16:01:51 -08001555
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 p = _value.ParseName( p );
1557 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 return 0;
1559 }
Lee Thomason67d61312012-01-24 16:01:51 -08001560
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001562 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 return p;
1564 }
Lee Thomason67d61312012-01-24 16:01:51 -08001565
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 p = XMLNode::ParseDeep( p, strPair );
1567 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001568}
1569
1570
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571
1572XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 }
1577 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1578 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1579 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1580 }
1581 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582}
1583
1584
1585bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1586{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001587 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 const XMLElement* other = compare->ToElement();
1589 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 const XMLAttribute* a=FirstAttribute();
1592 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001593
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 while ( a && b ) {
1595 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1596 return false;
1597 }
1598 a = a->Next();
1599 b = b->Next();
1600 }
1601 if ( a || b ) {
1602 // different count
1603 return false;
1604 }
1605 return true;
1606 }
1607 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001608}
1609
1610
Lee Thomason751da522012-02-10 08:50:51 -08001611bool XMLElement::Accept( XMLVisitor* visitor ) const
1612{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001613 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1616 if ( !node->Accept( visitor ) ) {
1617 break;
1618 }
1619 }
1620 }
1621 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001622}
Lee Thomason56bdd022012-02-09 18:16:58 -08001623
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624
Lee Thomason3f57d272012-01-11 15:30:03 -08001625// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001626
1627// Warning: List must match 'enum XMLError'
1628const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1629 "XML_SUCCESS",
1630 "XML_NO_ATTRIBUTE",
1631 "XML_WRONG_ATTRIBUTE_TYPE",
1632 "XML_ERROR_FILE_NOT_FOUND",
1633 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1634 "XML_ERROR_FILE_READ_ERROR",
1635 "XML_ERROR_ELEMENT_MISMATCH",
1636 "XML_ERROR_PARSING_ELEMENT",
1637 "XML_ERROR_PARSING_ATTRIBUTE",
1638 "XML_ERROR_IDENTIFYING_TAG",
1639 "XML_ERROR_PARSING_TEXT",
1640 "XML_ERROR_PARSING_CDATA",
1641 "XML_ERROR_PARSING_COMMENT",
1642 "XML_ERROR_PARSING_DECLARATION",
1643 "XML_ERROR_PARSING_UNKNOWN",
1644 "XML_ERROR_EMPTY_DOCUMENT",
1645 "XML_ERROR_MISMATCHED_ELEMENT",
1646 "XML_ERROR_PARSING",
1647 "XML_CAN_NOT_CONVERT_TEXT",
1648 "XML_NO_TEXT_NODE"
1649};
1650
1651
Lee Thomason624d43f2012-10-12 10:58:48 -07001652XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _writeBOM( false ),
1655 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001656 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001657 _whitespace( whitespace ),
1658 _errorStr1( 0 ),
1659 _errorStr2( 0 ),
1660 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001661{
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001663}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001664
1665
Lee Thomason3f57d272012-01-11 15:30:03 -08001666XMLDocument::~XMLDocument()
1667{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001668 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001669}
1670
1671
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001672void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001673{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001674 DeleteChildren();
1675
Dmitry-Meab37df82014-11-28 12:08:36 +03001676#ifdef DEBUG
1677 const bool hadError = Error();
1678#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 _errorID = XML_NO_ERROR;
1680 _errorStr1 = 0;
1681 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001682
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 delete [] _charBuffer;
1684 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001685
1686#if 0
1687 _textPool.Trace( "text" );
1688 _elementPool.Trace( "element" );
1689 _commentPool.Trace( "comment" );
1690 _attributePool.Trace( "attribute" );
1691#endif
1692
1693#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001694 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001695 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1696 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1697 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1698 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1699 }
1700#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001701}
1702
Lee Thomason3f57d272012-01-11 15:30:03 -08001703
Lee Thomason2c85a712012-01-31 08:24:24 -08001704XMLElement* XMLDocument::NewElement( const char* name )
1705{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001706 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1708 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 ele->SetName( name );
1710 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001711}
1712
1713
Lee Thomason1ff38e02012-02-14 18:18:16 -08001714XMLComment* XMLDocument::NewComment( const char* str )
1715{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001716 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1718 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001719 comment->SetValue( str );
1720 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001721}
1722
1723
1724XMLText* XMLDocument::NewText( const char* str )
1725{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001726 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1728 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 text->SetValue( str );
1730 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001731}
1732
1733
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001734XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1735{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001736 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1738 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1740 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001741}
1742
1743
1744XMLUnknown* XMLDocument::NewUnknown( const char* str )
1745{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001746 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1748 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 unk->SetValue( str );
1750 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001751}
1752
Dmitry-Me01578db2014-08-19 10:18:48 +04001753static FILE* callfopen( const char* filepath, const char* mode )
1754{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001755 TIXMLASSERT( filepath );
1756 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001757#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1758 FILE* fp = 0;
1759 errno_t err = fopen_s( &fp, filepath, mode );
1760 if ( err ) {
1761 return 0;
1762 }
1763#else
1764 FILE* fp = fopen( filepath, mode );
1765#endif
1766 return fp;
1767}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001768
1769void XMLDocument::DeleteNode( XMLNode* node ) {
1770 TIXMLASSERT( node );
1771 TIXMLASSERT(node->_document == this );
1772 if (node->_parent) {
1773 node->_parent->DeleteChild( node );
1774 }
1775 else {
1776 // Isn't in the tree.
1777 // Use the parent delete.
1778 // Also, we need to mark it tracked: we 'know'
1779 // it was never used.
1780 node->_memPool->SetTracked();
1781 // Call the static XMLNode version:
1782 XMLNode::DeleteNode(node);
1783 }
1784}
1785
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001786
Lee Thomason2fa81722012-11-09 12:37:46 -08001787XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001788{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001789 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001790 FILE* fp = callfopen( filename, "rb" );
1791 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 }
1795 LoadFile( fp );
1796 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798}
1799
1800
Lee Thomason2fa81722012-11-09 12:37:46 -08001801XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001802{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001803 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001804
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001805 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001806 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001807 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1808 return _errorID;
1809 }
1810
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001812 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001814 if ( filelength == -1L ) {
1815 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1816 return _errorID;
1817 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001818
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001819 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001821 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001824
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 _charBuffer = new char[size+1];
1826 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 if ( read != size ) {
1828 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001829 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001831
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 if ( !p || !*p ) {
1838 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001841
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1843 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001844}
1845
1846
Lee Thomason2fa81722012-11-09 12:37:46 -08001847XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848{
Dmitry-Me01578db2014-08-19 10:18:48 +04001849 FILE* fp = callfopen( filename, "w" );
1850 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
1854 SaveFile(fp, compact);
1855 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001857}
1858
1859
Lee Thomason2fa81722012-11-09 12:37:46 -08001860XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001861{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 XMLPrinter stream( fp, compact );
1863 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001865}
1866
Lee Thomason1ff38e02012-02-14 18:18:16 -08001867
Lee Thomason2fa81722012-11-09 12:37:46 -08001868XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001869{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001870 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001871 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001872
Lee Thomason82d32002014-02-21 22:47:18 -08001873 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
1877 if ( len == (size_t)(-1) ) {
1878 len = strlen( p );
1879 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 _charBuffer = new char[ len+1 ];
1881 memcpy( _charBuffer, p, len );
1882 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001883
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 if ( !p || !*p ) {
1887 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001888 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001890
Thomas Roß1470edc2013-05-10 15:44:12 +02001891 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001892 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001893 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001894 // clean up now essentially dangling memory.
1895 // and the parse fail can put objects in the
1896 // pools that are dead and inaccessible.
1897 DeleteChildren();
1898 _elementPool.Clear();
1899 _attributePool.Clear();
1900 _textPool.Clear();
1901 _commentPool.Clear();
1902 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001904}
1905
1906
PKEuS1c5f99e2013-07-06 11:28:39 +02001907void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001908{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 XMLPrinter stdStreamer( stdout );
1910 if ( !streamer ) {
1911 streamer = &stdStreamer;
1912 }
1913 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001914}
1915
1916
Lee Thomason2fa81722012-11-09 12:37:46 -08001917void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001918{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001919 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 _errorID = error;
1921 _errorStr1 = str1;
1922 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001923}
1924
Lee Thomason331596e2014-09-11 14:56:43 -07001925const char* XMLDocument::ErrorName() const
1926{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001927 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001928 return _errorNames[_errorID];
1929}
Lee Thomason5cae8972012-01-24 18:03:07 -08001930
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001931void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001932{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001933 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 static const int LEN = 20;
1935 char buf1[LEN] = { 0 };
1936 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001937
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 if ( _errorStr1 ) {
1939 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 if ( _errorStr2 ) {
1942 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001944
Lee Thomason331596e2014-09-11 14:56:43 -07001945 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1946 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001948}
1949
1950
PKEuS1bfb9542013-08-04 13:51:17 +02001951XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 _elementJustOpened( false ),
1953 _firstElement( true ),
1954 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001955 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001956 _textDepth( -1 ),
1957 _processEntities( true ),
1958 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 _entityFlag[i] = false;
1962 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 }
1964 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001965 const char entityValue = entities[i].value;
1966 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1967 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001969 _restrictedEntityFlag[(unsigned char)'&'] = true;
1970 _restrictedEntityFlag[(unsigned char)'<'] = true;
1971 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001973}
1974
1975
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001976void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001977{
1978 va_list va;
1979 va_start( va, format );
1980
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 if ( _fp ) {
1982 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 }
1984 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001985#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001986 #if defined(WINCE)
1987 int len = 512;
1988 do {
1989 len = len*2;
1990 char* str = new char[len]();
1991 len = _vsnprintf(str, len, format, va);
1992 delete[] str;
1993 }while (len < 0);
1994 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001995 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001996 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997#else
1998 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001999#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 // Close out and re-start the va-args
2001 va_end( va );
2002 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07002003 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2004#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002005 #if defined(WINCE)
2006 _vsnprintf( p, len+1, format, va );
2007 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002008 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002009 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002010#else
2011 vsnprintf( p, len+1, format, va );
2012#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002014 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002015}
2016
2017
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002018void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 for( int i=0; i<depth; ++i ) {
2021 Print( " " );
2022 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002023}
2024
2025
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002026void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002027{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 // Look for runs of bytes between entities to print.
2029 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002031
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 while ( *q ) {
2034 // Remember, char is sometimes signed. (How many times has that bitten me?)
2035 if ( *q > 0 && *q < ENTITY_RANGE ) {
2036 // Check for entities. If one is found, flush
2037 // the stream up until the entity, write the
2038 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002039 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 while ( p < q ) {
2041 Print( "%c", *p );
2042 ++p;
2043 }
2044 for( int i=0; i<NUM_ENTITIES; ++i ) {
2045 if ( entities[i].value == *q ) {
2046 Print( "&%s;", entities[i].pattern );
2047 break;
2048 }
2049 }
2050 ++p;
2051 }
2052 }
2053 ++q;
2054 }
2055 }
2056 // Flush the remaining string. This will be the entire
2057 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 Print( "%s", p );
2060 }
Lee Thomason857b8682012-01-25 17:50:25 -08002061}
2062
U-Stream\Leeae25a442012-02-17 17:48:16 -08002063
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002064void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002067 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 -07002068 Print( "%s", bom );
2069 }
2070 if ( writeDec ) {
2071 PushDeclaration( "xml version=\"1.0\"" );
2072 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002073}
2074
2075
Uli Kusterer593a33d2014-02-01 12:48:51 +01002076void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002077{
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 SealElement();
2080 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002082
Uli Kusterer593a33d2014-02-01 12:48:51 +01002083 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002085 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002086 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002089
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 _elementJustOpened = true;
2092 _firstElement = false;
2093 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002094}
2095
2096
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002097void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002098{
Lee Thomason624d43f2012-10-12 10:58:48 -07002099 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 Print( " %s=\"", name );
2101 PrintString( value, false );
2102 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002103}
2104
2105
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002106void XMLPrinter::PushAttribute( const char* name, int v )
2107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 char buf[BUF_SIZE];
2109 XMLUtil::ToStr( v, buf, BUF_SIZE );
2110 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002111}
2112
2113
2114void XMLPrinter::PushAttribute( const char* name, unsigned v )
2115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 char buf[BUF_SIZE];
2117 XMLUtil::ToStr( v, buf, BUF_SIZE );
2118 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002119}
2120
2121
2122void XMLPrinter::PushAttribute( const char* name, bool v )
2123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 char buf[BUF_SIZE];
2125 XMLUtil::ToStr( v, buf, BUF_SIZE );
2126 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002127}
2128
2129
2130void XMLPrinter::PushAttribute( const char* name, double v )
2131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 char buf[BUF_SIZE];
2133 XMLUtil::ToStr( v, buf, BUF_SIZE );
2134 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002135}
2136
2137
Uli Kustererca412e82014-02-01 13:35:05 +01002138void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002139{
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 --_depth;
2141 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002142
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "/>" );
2145 }
2146 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002147 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
2151 Print( "</%s>", name );
2152 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002153
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 if ( _textDepth == _depth ) {
2155 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Uli Kustererca412e82014-02-01 13:35:05 +01002157 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 Print( "\n" );
2159 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002161}
2162
2163
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002164void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002165{
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002168}
2169
2170
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002171void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002172{
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002174
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 SealElement();
2177 }
2178 if ( cdata ) {
2179 Print( "<![CDATA[" );
2180 Print( "%s", text );
2181 Print( "]]>" );
2182 }
2183 else {
2184 PrintString( text, true );
2185 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002186}
2187
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002188void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 char buf[BUF_SIZE];
2191 XMLUtil::ToStr( value, buf, BUF_SIZE );
2192 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002193}
2194
2195
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002196void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 char buf[BUF_SIZE];
2199 XMLUtil::ToStr( value, buf, BUF_SIZE );
2200 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002201}
2202
2203
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002204void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 char buf[BUF_SIZE];
2207 XMLUtil::ToStr( value, buf, BUF_SIZE );
2208 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002209}
2210
2211
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002212void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 char buf[BUF_SIZE];
2215 XMLUtil::ToStr( value, buf, BUF_SIZE );
2216 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002217}
2218
2219
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002220void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 char buf[BUF_SIZE];
2223 XMLUtil::ToStr( value, buf, BUF_SIZE );
2224 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002225}
2226
Lee Thomason5cae8972012-01-24 18:03:07 -08002227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002229{
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 SealElement();
2232 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002239}
Lee Thomason751da522012-02-10 08:50:51 -08002240
2241
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002242void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002243{
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 SealElement();
2246 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002253}
2254
2255
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002256void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002257{
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 SealElement();
2260 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002265 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002267}
2268
2269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002271{
Lee Thomason624d43f2012-10-12 10:58:48 -07002272 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 if ( doc.HasBOM() ) {
2274 PushHeader( true, false );
2275 }
2276 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002277}
2278
2279
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002280bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002281{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002282 const XMLElement* parentElem = element.Parent()->ToElement();
2283 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2284 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 while ( attribute ) {
2286 PushAttribute( attribute->Name(), attribute->Value() );
2287 attribute = attribute->Next();
2288 }
2289 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002290}
2291
2292
Uli Kustererca412e82014-02-01 13:35:05 +01002293bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002294{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002295 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002297}
2298
2299
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002300bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 PushText( text.Value(), text.CData() );
2303 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002304}
2305
2306
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002307bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 PushComment( comment.Value() );
2310 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002311}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002313bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002314{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 PushDeclaration( declaration.Value() );
2316 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002317}
2318
2319
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002320bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 PushUnknown( unknown.Value() );
2323 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002324}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002325
Lee Thomason685b8952012-11-12 13:00:06 -08002326} // namespace tinyxml2
2327