blob: 7b975c98d22d38cc4a581e5d4325645512fe3b0e [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 Thomason624d43f2012-10-12 10:58:48 -0700858 if ( !_document->Error() ) {
859 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
861 break;
862 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800863
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400864 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400866 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800868 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800870 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400871 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 return p;
873 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 // Handle an end tag returned to this level.
876 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400878 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
882 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400883 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 else if ( !endTag.Empty() ) {
886 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400887 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400890 if ( mismatch ) {
891 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500892 DeleteNode( node );
893 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
JayXondbfdd8f2014-12-12 20:07:14 -0500896 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 }
898 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800899}
900
Dmitry-Mee3225b12014-09-03 11:03:11 +0400901void XMLNode::DeleteNode( XMLNode* node )
902{
903 if ( node == 0 ) {
904 return;
905 }
906 MemPool* pool = node->_memPool;
907 node->~XMLNode();
908 pool->Free( node );
909}
910
Lee Thomason5492a1c2012-01-23 15:32:10 -0800911// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800912char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 const char* start = p;
915 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700918 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 }
920 return p;
921 }
922 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
924 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 flags |= StrPair::COLLAPSE_WHITESPACE;
926 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700927
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 if ( p && *p ) {
933 return p-1;
934 }
935 }
936 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800937}
938
939
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
946 text->SetCData( this->CData() );
947 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
951bool XMLText::ShallowEqual( const XMLNode* compare ) const
952{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400953 const XMLText* text = compare->ToText();
954 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
Lee Thomason56bdd022012-02-09 18:16:58 -0800958bool XMLText::Accept( XMLVisitor* visitor ) const
959{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300960 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800962}
963
964
Lee Thomason3f57d272012-01-11 15:30:03 -0800965// --------- XMLComment ---------- //
966
Lee Thomasone4422302012-01-20 17:59:50 -0800967XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800968{
969}
970
971
Lee Thomasonce0763e2012-01-11 15:43:54 -0800972XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800973{
Lee Thomason3f57d272012-01-11 15:30:03 -0800974}
975
976
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800977char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 // Comment parses as text.
980 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800986}
987
988
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
990{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
995 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996}
997
998
999bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1000{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001001 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001002 const XMLComment* comment = compare->ToComment();
1003 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
Lee Thomason751da522012-02-10 08:50:51 -08001007bool XMLComment::Accept( XMLVisitor* visitor ) const
1008{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001009 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001011}
Lee Thomason56bdd022012-02-09 18:16:58 -08001012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014// --------- XMLDeclaration ---------- //
1015
1016XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1017{
1018}
1019
1020
1021XMLDeclaration::~XMLDeclaration()
1022{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001024}
1025
1026
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001027char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 // Declaration parses as text.
1030 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001036}
1037
1038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001039XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1045 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046}
1047
1048
1049bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1050{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001051 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001052 const XMLDeclaration* declaration = compare->ToDeclaration();
1053 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054}
1055
1056
1057
Lee Thomason50f97b22012-02-11 16:33:40 -08001058bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1059{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001060 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001062}
1063
1064// --------- XMLUnknown ---------- //
1065
1066XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1067{
1068}
1069
1070
1071XMLUnknown::~XMLUnknown()
1072{
1073}
1074
1075
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001076char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 // Unknown parses as text.
1079 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001080
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001086}
1087
1088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001089XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001092 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 }
1094 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1095 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001101 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001102 const XMLUnknown* unknown = compare->ToUnknown();
1103 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001104}
1105
1106
Lee Thomason50f97b22012-02-11 16:33:40 -08001107bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1108{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001109 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001111}
1112
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001113// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001114
1115const char* XMLAttribute::Name() const
1116{
1117 return _name.GetStr();
1118}
1119
1120const char* XMLAttribute::Value() const
1121{
1122 return _value.GetStr();
1123}
1124
Lee Thomason6f381b72012-03-02 12:59:39 -08001125char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( !p || !*p ) {
1130 return 0;
1131 }
Lee Thomason22aead12012-01-23 13:29:35 -08001132
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Skip white space before =
1134 p = XMLUtil::SkipWhiteSpace( p );
1135 if ( !p || *p != '=' ) {
1136 return 0;
1137 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 ++p; // move up to opening quote
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 char endTag[2] = { *p, 0 };
1146 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001147
Lee Thomason624d43f2012-10-12 10:58:48 -07001148 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001150}
1151
1152
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001153void XMLAttribute::SetName( const char* n )
1154{
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001156}
1157
1158
Lee Thomason2fa81722012-11-09 12:37:46 -08001159XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( XMLUtil::ToInt( Value(), value )) {
1162 return XML_NO_ERROR;
1163 }
1164 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165}
1166
1167
Lee Thomason2fa81722012-11-09 12:37:46 -08001168XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 if ( XMLUtil::ToUnsigned( Value(), value )) {
1171 return XML_NO_ERROR;
1172 }
1173 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174}
1175
1176
Lee Thomason2fa81722012-11-09 12:37:46 -08001177XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( XMLUtil::ToBool( Value(), value )) {
1180 return XML_NO_ERROR;
1181 }
1182 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001183}
1184
1185
Lee Thomason2fa81722012-11-09 12:37:46 -08001186XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( XMLUtil::ToFloat( Value(), value )) {
1189 return XML_NO_ERROR;
1190 }
1191 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001192}
1193
1194
Lee Thomason2fa81722012-11-09 12:37:46 -08001195XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::ToDouble( Value(), value )) {
1198 return XML_NO_ERROR;
1199 }
1200 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201}
1202
1203
1204void XMLAttribute::SetAttribute( const char* v )
1205{
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210void XMLAttribute::SetAttribute( int v )
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 char buf[BUF_SIZE];
1213 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001216
1217
1218void XMLAttribute::SetAttribute( unsigned v )
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 char buf[BUF_SIZE];
1221 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223}
1224
1225
1226void XMLAttribute::SetAttribute( bool v )
1227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 char buf[BUF_SIZE];
1229 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001231}
1232
1233void XMLAttribute::SetAttribute( double v )
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 char buf[BUF_SIZE];
1236 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001237 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240void XMLAttribute::SetAttribute( float v )
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 char buf[BUF_SIZE];
1243 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001244 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001245}
1246
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001247
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001248// --------- XMLElement ---------- //
1249XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _closingType( 0 ),
1251 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001252{
1253}
1254
1255
1256XMLElement::~XMLElement()
1257{
Lee Thomason624d43f2012-10-12 10:58:48 -07001258 while( _rootAttribute ) {
1259 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001260 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001263}
1264
1265
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001266const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1267{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001268 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1270 return a;
1271 }
1272 }
1273 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001274}
1275
1276
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001277const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 const XMLAttribute* a = FindAttribute( name );
1280 if ( !a ) {
1281 return 0;
1282 }
1283 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1284 return a->Value();
1285 }
1286 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001287}
1288
1289
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001290const char* XMLElement::GetText() const
1291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001293 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 }
1295 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296}
1297
1298
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001299void XMLElement::SetText( const char* inText )
1300{
Uli Kusterer869bb592014-01-21 01:36:16 +01001301 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001302 FirstChild()->SetValue( inText );
1303 else {
1304 XMLText* theText = GetDocument()->NewText( inText );
1305 InsertFirstChild( theText );
1306 }
1307}
1308
Lee Thomason5bb2d802014-01-24 10:42:57 -08001309
1310void XMLElement::SetText( int v )
1311{
1312 char buf[BUF_SIZE];
1313 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314 SetText( buf );
1315}
1316
1317
1318void XMLElement::SetText( unsigned v )
1319{
1320 char buf[BUF_SIZE];
1321 XMLUtil::ToStr( v, buf, BUF_SIZE );
1322 SetText( buf );
1323}
1324
1325
1326void XMLElement::SetText( bool v )
1327{
1328 char buf[BUF_SIZE];
1329 XMLUtil::ToStr( v, buf, BUF_SIZE );
1330 SetText( buf );
1331}
1332
1333
1334void XMLElement::SetText( float v )
1335{
1336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
1338 SetText( buf );
1339}
1340
1341
1342void XMLElement::SetText( double v )
1343{
1344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
1346 SetText( buf );
1347}
1348
1349
MortenMacFly4ee49f12013-01-14 20:03:14 +01001350XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001353 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 return XML_SUCCESS;
1356 }
1357 return XML_CAN_NOT_CONVERT_TEXT;
1358 }
1359 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001360}
1361
1362
MortenMacFly4ee49f12013-01-14 20:03:14 +01001363XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001366 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 return XML_SUCCESS;
1369 }
1370 return XML_CAN_NOT_CONVERT_TEXT;
1371 }
1372 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001373}
1374
1375
MortenMacFly4ee49f12013-01-14 20:03:14 +01001376XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001379 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 return XML_SUCCESS;
1382 }
1383 return XML_CAN_NOT_CONVERT_TEXT;
1384 }
1385 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001386}
1387
1388
MortenMacFly4ee49f12013-01-14 20:03:14 +01001389XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001392 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return XML_SUCCESS;
1395 }
1396 return XML_CAN_NOT_CONVERT_TEXT;
1397 }
1398 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001399}
1400
1401
MortenMacFly4ee49f12013-01-14 20:03:14 +01001402XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001405 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return XML_SUCCESS;
1408 }
1409 return XML_CAN_NOT_CONVERT_TEXT;
1410 }
1411 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001412}
1413
1414
1415
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 XMLAttribute* last = 0;
1419 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1424 break;
1425 }
1426 }
1427 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001428 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1430 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
1434 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001438 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441}
1442
1443
U-Stream\Leeae25a442012-02-17 17:48:16 -08001444void XMLElement::DeleteAttribute( const char* name )
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1449 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 }
1452 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001455 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 break;
1457 }
1458 prev = a;
1459 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001460}
1461
1462
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001463char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 const char* start = p;
1466 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 // Read the attributes.
1469 while( p ) {
1470 p = XMLUtil::SkipWhiteSpace( p );
1471 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 return 0;
1474 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001477 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001478 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1480 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001481 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001482
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001485 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 return 0;
1488 }
1489 // There is a minor bug here: if the attribute in the source xml
1490 // document is duplicated, it will not be detected and the
1491 // attribute will be doubly added. However, tracking the 'prevAttribute'
1492 // avoids re-scanning the attribute list. Preferring performance for
1493 // now, may reconsider in the future.
1494 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 }
1500 prevAttribute = attrib;
1501 }
1502 // end of the tag
1503 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 return p+2; // done; sealed element.
1506 }
1507 // end of the tag
1508 else if ( *p == '>' ) {
1509 ++p;
1510 break;
1511 }
1512 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
1516 }
1517 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001518}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001519
Dmitry-Mee3225b12014-09-03 11:03:11 +04001520void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1521{
1522 if ( attribute == 0 ) {
1523 return;
1524 }
1525 MemPool* pool = attribute->_memPool;
1526 attribute->~XMLAttribute();
1527 pool->Free( attribute );
1528}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Lee Thomason67d61312012-01-24 16:01:51 -08001530//
1531// <ele></ele>
1532// <ele>foo<b>bar</b></ele>
1533//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001534char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 // Read the element name.
1537 p = XMLUtil::SkipWhiteSpace( p );
1538 if ( !p ) {
1539 return 0;
1540 }
Lee Thomason67d61312012-01-24 16:01:51 -08001541
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // The closing element is the </element> form. It is
1543 // parsed just like a regular element then deleted from
1544 // the DOM.
1545 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 ++p;
1548 }
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 p = _value.ParseName( p );
1551 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return 0;
1553 }
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 return p;
1558 }
Lee Thomason67d61312012-01-24 16:01:51 -08001559
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 p = XMLNode::ParseDeep( p, strPair );
1561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001562}
1563
1564
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565
1566XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1572 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1573 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1574 }
1575 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001576}
1577
1578
1579bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1580{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001581 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 const XMLElement* other = compare->ToElement();
1583 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001584
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 const XMLAttribute* a=FirstAttribute();
1586 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 while ( a && b ) {
1589 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1590 return false;
1591 }
1592 a = a->Next();
1593 b = b->Next();
1594 }
1595 if ( a || b ) {
1596 // different count
1597 return false;
1598 }
1599 return true;
1600 }
1601 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001602}
1603
1604
Lee Thomason751da522012-02-10 08:50:51 -08001605bool XMLElement::Accept( XMLVisitor* visitor ) const
1606{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001607 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1610 if ( !node->Accept( visitor ) ) {
1611 break;
1612 }
1613 }
1614 }
1615 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001616}
Lee Thomason56bdd022012-02-09 18:16:58 -08001617
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001618
Lee Thomason3f57d272012-01-11 15:30:03 -08001619// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001620
1621// Warning: List must match 'enum XMLError'
1622const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1623 "XML_SUCCESS",
1624 "XML_NO_ATTRIBUTE",
1625 "XML_WRONG_ATTRIBUTE_TYPE",
1626 "XML_ERROR_FILE_NOT_FOUND",
1627 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1628 "XML_ERROR_FILE_READ_ERROR",
1629 "XML_ERROR_ELEMENT_MISMATCH",
1630 "XML_ERROR_PARSING_ELEMENT",
1631 "XML_ERROR_PARSING_ATTRIBUTE",
1632 "XML_ERROR_IDENTIFYING_TAG",
1633 "XML_ERROR_PARSING_TEXT",
1634 "XML_ERROR_PARSING_CDATA",
1635 "XML_ERROR_PARSING_COMMENT",
1636 "XML_ERROR_PARSING_DECLARATION",
1637 "XML_ERROR_PARSING_UNKNOWN",
1638 "XML_ERROR_EMPTY_DOCUMENT",
1639 "XML_ERROR_MISMATCHED_ELEMENT",
1640 "XML_ERROR_PARSING",
1641 "XML_CAN_NOT_CONVERT_TEXT",
1642 "XML_NO_TEXT_NODE"
1643};
1644
1645
Lee Thomason624d43f2012-10-12 10:58:48 -07001646XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 _writeBOM( false ),
1649 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001650 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _whitespace( whitespace ),
1652 _errorStr1( 0 ),
1653 _errorStr2( 0 ),
1654 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655{
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001657}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001658
1659
Lee Thomason3f57d272012-01-11 15:30:03 -08001660XMLDocument::~XMLDocument()
1661{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001662 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001663}
1664
1665
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001667{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001668 DeleteChildren();
1669
Dmitry-Meab37df82014-11-28 12:08:36 +03001670#ifdef DEBUG
1671 const bool hadError = Error();
1672#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _errorID = XML_NO_ERROR;
1674 _errorStr1 = 0;
1675 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001676
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 delete [] _charBuffer;
1678 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001679
1680#if 0
1681 _textPool.Trace( "text" );
1682 _elementPool.Trace( "element" );
1683 _commentPool.Trace( "comment" );
1684 _attributePool.Trace( "attribute" );
1685#endif
1686
1687#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001688 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001689 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1690 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1691 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1692 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1693 }
1694#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001695}
1696
Lee Thomason3f57d272012-01-11 15:30:03 -08001697
Lee Thomason2c85a712012-01-31 08:24:24 -08001698XMLElement* XMLDocument::NewElement( const char* name )
1699{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001700 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1702 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 ele->SetName( name );
1704 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001705}
1706
1707
Lee Thomason1ff38e02012-02-14 18:18:16 -08001708XMLComment* XMLDocument::NewComment( const char* str )
1709{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001710 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1712 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 comment->SetValue( str );
1714 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001715}
1716
1717
1718XMLText* XMLDocument::NewText( const char* str )
1719{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001720 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1722 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 text->SetValue( str );
1724 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001725}
1726
1727
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001728XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1729{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001730 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1732 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1734 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001735}
1736
1737
1738XMLUnknown* XMLDocument::NewUnknown( const char* str )
1739{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001740 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1742 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 unk->SetValue( str );
1744 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001745}
1746
Dmitry-Me01578db2014-08-19 10:18:48 +04001747static FILE* callfopen( const char* filepath, const char* mode )
1748{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001749 TIXMLASSERT( filepath );
1750 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001751#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1752 FILE* fp = 0;
1753 errno_t err = fopen_s( &fp, filepath, mode );
1754 if ( err ) {
1755 return 0;
1756 }
1757#else
1758 FILE* fp = fopen( filepath, mode );
1759#endif
1760 return fp;
1761}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001762
1763void XMLDocument::DeleteNode( XMLNode* node ) {
1764 TIXMLASSERT( node );
1765 TIXMLASSERT(node->_document == this );
1766 if (node->_parent) {
1767 node->_parent->DeleteChild( node );
1768 }
1769 else {
1770 // Isn't in the tree.
1771 // Use the parent delete.
1772 // Also, we need to mark it tracked: we 'know'
1773 // it was never used.
1774 node->_memPool->SetTracked();
1775 // Call the static XMLNode version:
1776 XMLNode::DeleteNode(node);
1777 }
1778}
1779
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001780
Lee Thomason2fa81722012-11-09 12:37:46 -08001781XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001782{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001783 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001784 FILE* fp = callfopen( filename, "rb" );
1785 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 }
1789 LoadFile( fp );
1790 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001792}
1793
1794
Lee Thomason2fa81722012-11-09 12:37:46 -08001795XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001797 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001799 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001800 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001801 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1802 return _errorID;
1803 }
1804
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001806 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001808 if ( filelength == -1L ) {
1809 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1810 return _errorID;
1811 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001812
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001813 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001815 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001818
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 _charBuffer = new char[size+1];
1820 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 if ( read != size ) {
1822 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001825
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001827
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 if ( !p || !*p ) {
1832 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001835
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1837 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001838}
1839
1840
Lee Thomason2fa81722012-11-09 12:37:46 -08001841XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001842{
Dmitry-Me01578db2014-08-19 10:18:48 +04001843 FILE* fp = callfopen( filename, "w" );
1844 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 }
1848 SaveFile(fp, compact);
1849 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001851}
1852
1853
Lee Thomason2fa81722012-11-09 12:37:46 -08001854XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001855{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 XMLPrinter stream( fp, compact );
1857 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001859}
1860
Lee Thomason1ff38e02012-02-14 18:18:16 -08001861
Lee Thomason2fa81722012-11-09 12:37:46 -08001862XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001863{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001864 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001865
Lee Thomason82d32002014-02-21 22:47:18 -08001866 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
1870 if ( len == (size_t)(-1) ) {
1871 len = strlen( p );
1872 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 _charBuffer = new char[ len+1 ];
1874 memcpy( _charBuffer, p, len );
1875 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001876
Dmitry-Me5b4a5162014-12-23 17:36:28 +03001877 const char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 if ( !p || !*p ) {
1881 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001884
Thomas Roß1470edc2013-05-10 15:44:12 +02001885 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001886 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001887 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001888 // clean up now essentially dangling memory.
1889 // and the parse fail can put objects in the
1890 // pools that are dead and inaccessible.
1891 DeleteChildren();
1892 _elementPool.Clear();
1893 _attributePool.Clear();
1894 _textPool.Clear();
1895 _commentPool.Clear();
1896 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001898}
1899
1900
PKEuS1c5f99e2013-07-06 11:28:39 +02001901void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001902{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 XMLPrinter stdStreamer( stdout );
1904 if ( !streamer ) {
1905 streamer = &stdStreamer;
1906 }
1907 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001908}
1909
1910
Lee Thomason2fa81722012-11-09 12:37:46 -08001911void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001912{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001913 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 _errorID = error;
1915 _errorStr1 = str1;
1916 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001917}
1918
Lee Thomason331596e2014-09-11 14:56:43 -07001919const char* XMLDocument::ErrorName() const
1920{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001921 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001922 return _errorNames[_errorID];
1923}
Lee Thomason5cae8972012-01-24 18:03:07 -08001924
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001925void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001926{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001927 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 static const int LEN = 20;
1929 char buf1[LEN] = { 0 };
1930 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001931
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 if ( _errorStr1 ) {
1933 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001935 if ( _errorStr2 ) {
1936 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001938
Lee Thomason331596e2014-09-11 14:56:43 -07001939 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1940 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001942}
1943
1944
PKEuS1bfb9542013-08-04 13:51:17 +02001945XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 _elementJustOpened( false ),
1947 _firstElement( true ),
1948 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001949 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _textDepth( -1 ),
1951 _processEntities( true ),
1952 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 _entityFlag[i] = false;
1956 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
1958 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001959 const char entityValue = entities[i].value;
1960 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1961 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001963 _restrictedEntityFlag[(unsigned char)'&'] = true;
1964 _restrictedEntityFlag[(unsigned char)'<'] = true;
1965 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001967}
1968
1969
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001970void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001971{
1972 va_list va;
1973 va_start( va, format );
1974
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 if ( _fp ) {
1976 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 }
1978 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001979#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001980 #if defined(WINCE)
1981 int len = 512;
1982 do {
1983 len = len*2;
1984 char* str = new char[len]();
1985 len = _vsnprintf(str, len, format, va);
1986 delete[] str;
1987 }while (len < 0);
1988 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001989 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001990 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001991#else
1992 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001993#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 // Close out and re-start the va-args
1995 va_end( va );
1996 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001997 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1998#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001999 #if defined(WINCE)
2000 _vsnprintf( p, len+1, format, va );
2001 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002002 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002003 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002004#else
2005 vsnprintf( p, len+1, format, va );
2006#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002008 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002009}
2010
2011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002012void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002013{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 for( int i=0; i<depth; ++i ) {
2015 Print( " " );
2016 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002017}
2018
2019
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002020void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 // Look for runs of bytes between entities to print.
2023 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002025
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 while ( *q ) {
2028 // Remember, char is sometimes signed. (How many times has that bitten me?)
2029 if ( *q > 0 && *q < ENTITY_RANGE ) {
2030 // Check for entities. If one is found, flush
2031 // the stream up until the entity, write the
2032 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002033 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 while ( p < q ) {
2035 Print( "%c", *p );
2036 ++p;
2037 }
2038 for( int i=0; i<NUM_ENTITIES; ++i ) {
2039 if ( entities[i].value == *q ) {
2040 Print( "&%s;", entities[i].pattern );
2041 break;
2042 }
2043 }
2044 ++p;
2045 }
2046 }
2047 ++q;
2048 }
2049 }
2050 // Flush the remaining string. This will be the entire
2051 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 Print( "%s", p );
2054 }
Lee Thomason857b8682012-01-25 17:50:25 -08002055}
2056
U-Stream\Leeae25a442012-02-17 17:48:16 -08002057
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002058void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002061 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 -07002062 Print( "%s", bom );
2063 }
2064 if ( writeDec ) {
2065 PushDeclaration( "xml version=\"1.0\"" );
2066 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002067}
2068
2069
Uli Kusterer593a33d2014-02-01 12:48:51 +01002070void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002071{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002072 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002074
Uli Kusterer593a33d2014-02-01 12:48:51 +01002075 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002077 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002078 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002081
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _elementJustOpened = true;
2084 _firstElement = false;
2085 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002086}
2087
2088
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002089void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002090{
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 Print( " %s=\"", name );
2093 PrintString( value, false );
2094 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002095}
2096
2097
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002098void XMLPrinter::PushAttribute( const char* name, int v )
2099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( v, buf, BUF_SIZE );
2102 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103}
2104
2105
2106void XMLPrinter::PushAttribute( const char* name, unsigned 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, bool 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, double 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
Uli Kustererca412e82014-02-01 13:35:05 +01002130void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002131{
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 --_depth;
2133 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002134
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 Print( "/>" );
2137 }
2138 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002139 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
2143 Print( "</%s>", name );
2144 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002145
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 if ( _textDepth == _depth ) {
2147 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
Uli Kustererca412e82014-02-01 13:35:05 +01002149 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( "\n" );
2151 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002153}
2154
2155
Dmitry-Mea092bc12014-12-23 17:57:05 +03002156void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002157{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002158 if ( !_elementJustOpened ) {
2159 return;
2160 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002163}
2164
2165
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002166void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002167{
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002169
Dmitry-Mea092bc12014-12-23 17:57:05 +03002170 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 if ( cdata ) {
2172 Print( "<![CDATA[" );
2173 Print( "%s", text );
2174 Print( "]]>" );
2175 }
2176 else {
2177 PrintString( text, true );
2178 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002179}
2180
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002181void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 char buf[BUF_SIZE];
2184 XMLUtil::ToStr( value, buf, BUF_SIZE );
2185 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002186}
2187
2188
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002189void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 char buf[BUF_SIZE];
2192 XMLUtil::ToStr( value, buf, BUF_SIZE );
2193 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002194}
2195
2196
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002197void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 char buf[BUF_SIZE];
2200 XMLUtil::ToStr( value, buf, BUF_SIZE );
2201 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002202}
2203
2204
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002205void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 char buf[BUF_SIZE];
2208 XMLUtil::ToStr( value, buf, BUF_SIZE );
2209 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002210}
2211
2212
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002213void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 char buf[BUF_SIZE];
2216 XMLUtil::ToStr( value, buf, BUF_SIZE );
2217 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002218}
2219
Lee Thomason5cae8972012-01-24 18:03:07 -08002220
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002221void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002222{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002223 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002230}
Lee Thomason751da522012-02-10 08:50:51 -08002231
2232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002233void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002235 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242}
2243
2244
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002245void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002246{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002247 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
2256
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002257bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002258{
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 if ( doc.HasBOM() ) {
2261 PushHeader( true, false );
2262 }
2263 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002264}
2265
2266
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002267bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002268{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002269 const XMLElement* parentElem = element.Parent()->ToElement();
2270 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2271 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 while ( attribute ) {
2273 PushAttribute( attribute->Name(), attribute->Value() );
2274 attribute = attribute->Next();
2275 }
2276 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002277}
2278
2279
Uli Kustererca412e82014-02-01 13:35:05 +01002280bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002281{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002282 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002284}
2285
2286
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002287bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002289 PushText( text.Value(), text.CData() );
2290 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002291}
2292
2293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 PushComment( comment.Value() );
2297 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002298}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002300bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 PushDeclaration( declaration.Value() );
2303 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304}
2305
2306
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002307bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 PushUnknown( unknown.Value() );
2310 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002311}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002312
Lee Thomason685b8952012-11-12 13:00:06 -08002313} // namespace tinyxml2
2314