blob: fc746de3159e24f67fca4f7cf3b5d52153862218 [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 ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700542 returnNode = new (_commentPool.Alloc()) XMLComment( this );
543 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += commentHeaderLen;
545 }
546 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += cdataHeaderLen;
551 text->SetCData( true );
552 }
553 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += dtdHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 returnNode = new (_elementPool.Alloc()) XMLElement( this );
560 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 p += elementHeaderLen;
562 }
563 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_textPool.Alloc()) XMLText( this );
565 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p = start; // Back it up, all the text counts.
567 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800568
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 *node = returnNode;
570 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571}
572
573
Lee Thomason751da522012-02-10 08:50:51 -0800574bool XMLDocument::Accept( XMLVisitor* visitor ) const
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( visitor->VisitEnter( *this ) ) {
577 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
578 if ( !node->Accept( visitor ) ) {
579 break;
580 }
581 }
582 }
583 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800584}
Lee Thomason56bdd022012-02-09 18:16:58 -0800585
586
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587// --------- XMLNode ----------- //
588
589XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700590 _document( doc ),
591 _parent( 0 ),
592 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200593 _prev( 0 ), _next( 0 ),
594 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596}
597
598
599XMLNode::~XMLNode()
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 if ( _parent ) {
603 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800605}
606
Michael Daumling21626882013-10-22 17:03:37 +0200607const char* XMLNode::Value() const
608{
609 return _value.GetStr();
610}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800612void XMLNode::SetValue( const char* str, bool staticMem )
613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
617 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620}
621
622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800623void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800624{
Lee Thomason624d43f2012-10-12 10:58:48 -0700625 while( _firstChild ) {
626 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700628
Dmitry-Mee3225b12014-09-03 11:03:11 +0400629 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800632}
633
634
635void XMLNode::Unlink( XMLNode* child )
636{
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child == _firstChild ) {
638 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 if ( child == _lastChild ) {
641 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
Lee Thomasond923c672012-01-23 08:44:25 -0800643
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 if ( child->_prev ) {
645 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( child->_next ) {
648 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700650 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651}
652
653
U-Stream\Leeae25a442012-02-17 17:48:16 -0800654void XMLNode::DeleteChild( XMLNode* node )
655{
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400657 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800658}
659
660
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
662{
Michael Daumlinged523282013-10-23 07:47:29 +0200663 if (addThis->_document != _document)
664 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700665
Michael Daumlinged523282013-10-23 07:47:29 +0200666 if (addThis->_parent)
667 addThis->_parent->Unlink( addThis );
668 else
669 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700670
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 if ( _lastChild ) {
672 TIXMLASSERT( _firstChild );
673 TIXMLASSERT( _lastChild->_next == 0 );
674 _lastChild->_next = addThis;
675 addThis->_prev = _lastChild;
676 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 }
680 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 TIXMLASSERT( _firstChild == 0 );
682 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800683
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 addThis->_prev = 0;
685 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689}
690
691
Lee Thomason1ff38e02012-02-14 18:18:16 -0800692XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
693{
Michael Daumlinged523282013-10-23 07:47:29 +0200694 if (addThis->_document != _document)
695 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700696
Michael Daumlinged523282013-10-23 07:47:29 +0200697 if (addThis->_parent)
698 addThis->_parent->Unlink( addThis );
699 else
700 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700701
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 if ( _firstChild ) {
703 TIXMLASSERT( _lastChild );
704 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 _firstChild->_prev = addThis;
707 addThis->_next = _firstChild;
708 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800709
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 }
712 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 TIXMLASSERT( _lastChild == 0 );
714 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800715
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 addThis->_prev = 0;
717 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700718 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400720 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800721}
722
723
724XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
725{
Michael Daumlinged523282013-10-23 07:47:29 +0200726 if (addThis->_document != _document)
727 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 return 0;
733 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 // The last node or the only node.
737 return InsertEndChild( addThis );
738 }
Michael Daumlinged523282013-10-23 07:47:29 +0200739 if (addThis->_parent)
740 addThis->_parent->Unlink( addThis );
741 else
742 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 addThis->_prev = afterThis;
744 addThis->_next = afterThis->_next;
745 afterThis->_next->_prev = addThis;
746 afterThis->_next = addThis;
747 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800749}
750
751
752
753
Lee Thomason56bdd022012-02-09 18:16:58 -0800754const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800755{
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 XMLElement* element = node->ToElement();
758 if ( element ) {
759 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
760 return element;
761 }
762 }
763 }
764 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800765}
766
767
Lee Thomason56bdd022012-02-09 18:16:58 -0800768const XMLElement* XMLNode::LastChildElement( const char* value ) const
769{
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 XMLElement* element = node->ToElement();
772 if ( element ) {
773 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
774 return element;
775 }
776 }
777 }
778 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800779}
780
781
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
783{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400784 for( XMLNode* node=this->_next; node; node = node->_next ) {
785 const XMLElement* element = node->ToElement();
786 if ( element
787 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
788 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700789 }
790 }
791 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792}
793
794
795const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
796{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400797 for( XMLNode* node=_prev; node; node = node->_prev ) {
798 const XMLElement* element = node->ToElement();
799 if ( element
800 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
801 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
803 }
804 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800805}
806
807
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800808char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800809{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 // This is a recursive method, but thinking about it "at the current level"
811 // it is a pretty simple flat list:
812 // <foo/>
813 // <!-- comment -->
814 //
815 // With a special case:
816 // <foo>
817 // </foo>
818 // <!-- comment -->
819 //
820 // Where the closing element (/foo) *must* be the next thing after the opening
821 // element, and the names must match. BUT the tricky bit is that the closing
822 // element will be read by the child.
823 //
824 // 'endTag' is the end tag for this node, it is returned by a call to a child.
825 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800826
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 while( p && *p ) {
828 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800829
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 if ( p == 0 || node == 0 ) {
832 break;
833 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800834
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 StrPair endTag;
836 p = node->ParseDeep( p, &endTag );
837 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400838 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 if ( !_document->Error() ) {
841 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
843 break;
844 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400846 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400848 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800850 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800852 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400853 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 return p;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 // Handle an end tag returned to this level.
858 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400860 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
864 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400865 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 }
867 else if ( !endTag.Empty() ) {
868 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400869 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
871 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400872 if ( mismatch ) {
873 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
874 p = 0;
875 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 }
877 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400878 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 node = 0;
880 }
881 if ( node ) {
882 this->InsertEndChild( node );
883 }
884 }
885 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800886}
887
Dmitry-Mee3225b12014-09-03 11:03:11 +0400888void XMLNode::DeleteNode( XMLNode* node )
889{
890 if ( node == 0 ) {
891 return;
892 }
893 MemPool* pool = node->_memPool;
894 node->~XMLNode();
895 pool->Free( node );
896}
897
Lee Thomason5492a1c2012-01-23 15:32:10 -0800898// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800899char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 const char* start = p;
902 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700903 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700905 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
907 return p;
908 }
909 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
911 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 flags |= StrPair::COLLAPSE_WHITESPACE;
913 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700914
Lee Thomason624d43f2012-10-12 10:58:48 -0700915 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
919 if ( p && *p ) {
920 return p-1;
921 }
922 }
923 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800924}
925
926
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800927XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
933 text->SetCData( this->CData() );
934 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935}
936
937
938bool XMLText::ShallowEqual( const XMLNode* compare ) const
939{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400940 const XMLText* text = compare->ToText();
941 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason56bdd022012-02-09 18:16:58 -0800945bool XMLText::Accept( XMLVisitor* visitor ) const
946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800948}
949
950
Lee Thomason3f57d272012-01-11 15:30:03 -0800951// --------- XMLComment ---------- //
952
Lee Thomasone4422302012-01-20 17:59:50 -0800953XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800954{
955}
956
957
Lee Thomasonce0763e2012-01-11 15:43:54 -0800958XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800959{
Lee Thomason3f57d272012-01-11 15:30:03 -0800960}
961
962
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800963char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800964{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 // Comment parses as text.
966 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800972}
973
974
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800975XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
980 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
981 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800982}
983
984
985bool XMLComment::ShallowEqual( const XMLNode* compare ) const
986{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400987 const XMLComment* comment = compare->ToComment();
988 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989}
990
991
Lee Thomason751da522012-02-10 08:50:51 -0800992bool XMLComment::Accept( XMLVisitor* visitor ) const
993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800995}
Lee Thomason56bdd022012-02-09 18:16:58 -0800996
997
Lee Thomason50f97b22012-02-11 16:33:40 -0800998// --------- XMLDeclaration ---------- //
999
1000XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1001{
1002}
1003
1004
1005XMLDeclaration::~XMLDeclaration()
1006{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001008}
1009
1010
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001011char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001012{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 // Declaration parses as text.
1014 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001015 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
1019 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001020}
1021
1022
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001026 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 }
1028 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1029 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001030}
1031
1032
1033bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1034{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001035 const XMLDeclaration* declaration = compare->ToDeclaration();
1036 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001037}
1038
1039
1040
Lee Thomason50f97b22012-02-11 16:33:40 -08001041bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001044}
1045
1046// --------- XMLUnknown ---------- //
1047
1048XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1049{
1050}
1051
1052
1053XMLUnknown::~XMLUnknown()
1054{
1055}
1056
1057
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001058char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 // Unknown parses as text.
1061 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001062
Lee Thomason624d43f2012-10-12 10:58:48 -07001063 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001065 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
1070
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001071XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 }
1076 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1077 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001078}
1079
1080
1081bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1082{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001083 const XMLUnknown* unknown = compare->ToUnknown();
1084 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001085}
1086
1087
Lee Thomason50f97b22012-02-11 16:33:40 -08001088bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001091}
1092
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001093// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001094
1095const char* XMLAttribute::Name() const
1096{
1097 return _name.GetStr();
1098}
1099
1100const char* XMLAttribute::Value() const
1101{
1102 return _value.GetStr();
1103}
1104
Lee Thomason6f381b72012-03-02 12:59:39 -08001105char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( !p || !*p ) {
1110 return 0;
1111 }
Lee Thomason22aead12012-01-23 13:29:35 -08001112
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 // Skip white space before =
1114 p = XMLUtil::SkipWhiteSpace( p );
1115 if ( !p || *p != '=' ) {
1116 return 0;
1117 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001118
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 ++p; // move up to opening quote
1120 p = XMLUtil::SkipWhiteSpace( p );
1121 if ( *p != '\"' && *p != '\'' ) {
1122 return 0;
1123 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001124
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 char endTag[2] = { *p, 0 };
1126 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001127
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001130}
1131
1132
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001133void XMLAttribute::SetName( const char* n )
1134{
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToInt( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToUnsigned( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
Lee Thomason2fa81722012-11-09 12:37:46 -08001157XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( XMLUtil::ToBool( Value(), value )) {
1160 return XML_NO_ERROR;
1161 }
1162 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163}
1164
1165
Lee Thomason2fa81722012-11-09 12:37:46 -08001166XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( XMLUtil::ToFloat( Value(), value )) {
1169 return XML_NO_ERROR;
1170 }
1171 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToDouble( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
1184void XMLAttribute::SetAttribute( const char* v )
1185{
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187}
1188
1189
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190void XMLAttribute::SetAttribute( int v )
1191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 char buf[BUF_SIZE];
1193 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001194 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001195}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001196
1197
1198void XMLAttribute::SetAttribute( unsigned v )
1199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 char buf[BUF_SIZE];
1201 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001203}
1204
1205
1206void XMLAttribute::SetAttribute( bool v )
1207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 char buf[BUF_SIZE];
1209 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001211}
1212
1213void XMLAttribute::SetAttribute( double v )
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 char buf[BUF_SIZE];
1216 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218}
1219
1220void XMLAttribute::SetAttribute( float v )
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 char buf[BUF_SIZE];
1223 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001225}
1226
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001227
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001228// --------- XMLElement ---------- //
1229XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _closingType( 0 ),
1231 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001232{
1233}
1234
1235
1236XMLElement::~XMLElement()
1237{
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 while( _rootAttribute ) {
1239 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001240 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001243}
1244
1245
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1247{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001248 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1250 return a;
1251 }
1252 }
1253 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001254}
1255
1256
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001257const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 const XMLAttribute* a = FindAttribute( name );
1260 if ( !a ) {
1261 return 0;
1262 }
1263 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1264 return a->Value();
1265 }
1266 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001267}
1268
1269
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001270const char* XMLElement::GetText() const
1271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001273 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 }
1275 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001276}
1277
1278
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001279void XMLElement::SetText( const char* inText )
1280{
Uli Kusterer869bb592014-01-21 01:36:16 +01001281 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001282 FirstChild()->SetValue( inText );
1283 else {
1284 XMLText* theText = GetDocument()->NewText( inText );
1285 InsertFirstChild( theText );
1286 }
1287}
1288
Lee Thomason5bb2d802014-01-24 10:42:57 -08001289
1290void XMLElement::SetText( int v )
1291{
1292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1294 SetText( buf );
1295}
1296
1297
1298void XMLElement::SetText( unsigned v )
1299{
1300 char buf[BUF_SIZE];
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1302 SetText( buf );
1303}
1304
1305
1306void XMLElement::SetText( bool v )
1307{
1308 char buf[BUF_SIZE];
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1310 SetText( buf );
1311}
1312
1313
1314void XMLElement::SetText( float v )
1315{
1316 char buf[BUF_SIZE];
1317 XMLUtil::ToStr( v, buf, BUF_SIZE );
1318 SetText( buf );
1319}
1320
1321
1322void XMLElement::SetText( double v )
1323{
1324 char buf[BUF_SIZE];
1325 XMLUtil::ToStr( v, buf, BUF_SIZE );
1326 SetText( buf );
1327}
1328
1329
MortenMacFly4ee49f12013-01-14 20:03:14 +01001330XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001333 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001334 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 return XML_SUCCESS;
1336 }
1337 return XML_CAN_NOT_CONVERT_TEXT;
1338 }
1339 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001340}
1341
1342
MortenMacFly4ee49f12013-01-14 20:03:14 +01001343XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001346 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001347 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 return XML_SUCCESS;
1349 }
1350 return XML_CAN_NOT_CONVERT_TEXT;
1351 }
1352 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001359 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001372 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001385 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return XML_SUCCESS;
1388 }
1389 return XML_CAN_NOT_CONVERT_TEXT;
1390 }
1391 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001392}
1393
1394
1395
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001396XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 XMLAttribute* last = 0;
1399 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001402 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1404 break;
1405 }
1406 }
1407 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1409 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001411 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 }
1413 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 }
1416 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001417 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001420}
1421
1422
U-Stream\Leeae25a442012-02-17 17:48:16 -08001423void XMLElement::DeleteAttribute( const char* name )
1424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1428 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 }
1431 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001434 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 break;
1436 }
1437 prev = a;
1438 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001439}
1440
1441
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001442char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 const char* start = p;
1445 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001446
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 // Read the attributes.
1448 while( p ) {
1449 p = XMLUtil::SkipWhiteSpace( p );
1450 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 return 0;
1453 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001454
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001456 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1458 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001459 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001460
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001463 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 return 0;
1466 }
1467 // There is a minor bug here: if the attribute in the source xml
1468 // document is duplicated, it will not be detected and the
1469 // attribute will be doubly added. However, tracking the 'prevAttribute'
1470 // avoids re-scanning the attribute list. Preferring performance for
1471 // now, may reconsider in the future.
1472 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 }
1475 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 }
1478 prevAttribute = attrib;
1479 }
1480 // end of the tag
1481 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 return p+2; // done; sealed element.
1484 }
1485 // end of the tag
1486 else if ( *p == '>' ) {
1487 ++p;
1488 break;
1489 }
1490 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 return 0;
1493 }
1494 }
1495 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001496}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001497
Dmitry-Mee3225b12014-09-03 11:03:11 +04001498void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1499{
1500 if ( attribute == 0 ) {
1501 return;
1502 }
1503 MemPool* pool = attribute->_memPool;
1504 attribute->~XMLAttribute();
1505 pool->Free( attribute );
1506}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001507
Lee Thomason67d61312012-01-24 16:01:51 -08001508//
1509// <ele></ele>
1510// <ele>foo<b>bar</b></ele>
1511//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001512char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 // Read the element name.
1515 p = XMLUtil::SkipWhiteSpace( p );
1516 if ( !p ) {
1517 return 0;
1518 }
Lee Thomason67d61312012-01-24 16:01:51 -08001519
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 // The closing element is the </element> form. It is
1521 // parsed just like a regular element then deleted from
1522 // the DOM.
1523 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001524 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 ++p;
1526 }
Lee Thomason67d61312012-01-24 16:01:51 -08001527
Lee Thomason624d43f2012-10-12 10:58:48 -07001528 p = _value.ParseName( p );
1529 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 return 0;
1531 }
Lee Thomason67d61312012-01-24 16:01:51 -08001532
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001534 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 return p;
1536 }
Lee Thomason67d61312012-01-24 16:01:51 -08001537
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 p = XMLNode::ParseDeep( p, strPair );
1539 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001540}
1541
1542
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001543
1544XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 }
1549 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1550 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1551 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1552 }
1553 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001554}
1555
1556
1557bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 const XMLElement* other = compare->ToElement();
1560 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001561
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 const XMLAttribute* a=FirstAttribute();
1563 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001564
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 while ( a && b ) {
1566 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1567 return false;
1568 }
1569 a = a->Next();
1570 b = b->Next();
1571 }
1572 if ( a || b ) {
1573 // different count
1574 return false;
1575 }
1576 return true;
1577 }
1578 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579}
1580
1581
Lee Thomason751da522012-02-10 08:50:51 -08001582bool XMLElement::Accept( XMLVisitor* visitor ) const
1583{
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1586 if ( !node->Accept( visitor ) ) {
1587 break;
1588 }
1589 }
1590 }
1591 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001592}
Lee Thomason56bdd022012-02-09 18:16:58 -08001593
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001594
Lee Thomason3f57d272012-01-11 15:30:03 -08001595// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001596
1597// Warning: List must match 'enum XMLError'
1598const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1599 "XML_SUCCESS",
1600 "XML_NO_ATTRIBUTE",
1601 "XML_WRONG_ATTRIBUTE_TYPE",
1602 "XML_ERROR_FILE_NOT_FOUND",
1603 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1604 "XML_ERROR_FILE_READ_ERROR",
1605 "XML_ERROR_ELEMENT_MISMATCH",
1606 "XML_ERROR_PARSING_ELEMENT",
1607 "XML_ERROR_PARSING_ATTRIBUTE",
1608 "XML_ERROR_IDENTIFYING_TAG",
1609 "XML_ERROR_PARSING_TEXT",
1610 "XML_ERROR_PARSING_CDATA",
1611 "XML_ERROR_PARSING_COMMENT",
1612 "XML_ERROR_PARSING_DECLARATION",
1613 "XML_ERROR_PARSING_UNKNOWN",
1614 "XML_ERROR_EMPTY_DOCUMENT",
1615 "XML_ERROR_MISMATCHED_ELEMENT",
1616 "XML_ERROR_PARSING",
1617 "XML_CAN_NOT_CONVERT_TEXT",
1618 "XML_NO_TEXT_NODE"
1619};
1620
1621
Lee Thomason624d43f2012-10-12 10:58:48 -07001622XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 _writeBOM( false ),
1625 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001626 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001627 _whitespace( whitespace ),
1628 _errorStr1( 0 ),
1629 _errorStr2( 0 ),
1630 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001631{
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001633}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001634
1635
Lee Thomason3f57d272012-01-11 15:30:03 -08001636XMLDocument::~XMLDocument()
1637{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001638 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001639}
1640
1641
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001642void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001643{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001644 DeleteChildren();
1645
Dmitry-Meab37df82014-11-28 12:08:36 +03001646#ifdef DEBUG
1647 const bool hadError = Error();
1648#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _errorID = XML_NO_ERROR;
1650 _errorStr1 = 0;
1651 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001652
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 delete [] _charBuffer;
1654 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001655
1656#if 0
1657 _textPool.Trace( "text" );
1658 _elementPool.Trace( "element" );
1659 _commentPool.Trace( "comment" );
1660 _attributePool.Trace( "attribute" );
1661#endif
1662
1663#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001664 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001665 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1666 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1667 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1668 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1669 }
1670#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001671}
1672
Lee Thomason3f57d272012-01-11 15:30:03 -08001673
Lee Thomason2c85a712012-01-31 08:24:24 -08001674XMLElement* XMLDocument::NewElement( const char* name )
1675{
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1677 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 ele->SetName( name );
1679 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001680}
1681
1682
Lee Thomason1ff38e02012-02-14 18:18:16 -08001683XMLComment* XMLDocument::NewComment( const char* str )
1684{
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1686 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 comment->SetValue( str );
1688 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001689}
1690
1691
1692XMLText* XMLDocument::NewText( const char* str )
1693{
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1695 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 text->SetValue( str );
1697 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001698}
1699
1700
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001701XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1702{
Lee Thomason624d43f2012-10-12 10:58:48 -07001703 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1704 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1706 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001707}
1708
1709
1710XMLUnknown* XMLDocument::NewUnknown( const char* str )
1711{
Lee Thomason624d43f2012-10-12 10:58:48 -07001712 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1713 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 unk->SetValue( str );
1715 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001716}
1717
Dmitry-Me01578db2014-08-19 10:18:48 +04001718static FILE* callfopen( const char* filepath, const char* mode )
1719{
1720#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1721 FILE* fp = 0;
1722 errno_t err = fopen_s( &fp, filepath, mode );
1723 if ( err ) {
1724 return 0;
1725 }
1726#else
1727 FILE* fp = fopen( filepath, mode );
1728#endif
1729 return fp;
1730}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001731
Lee Thomason2fa81722012-11-09 12:37:46 -08001732XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001734 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001735 FILE* fp = callfopen( filename, "rb" );
1736 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 }
1740 LoadFile( fp );
1741 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001743}
1744
1745
Lee Thomason2fa81722012-11-09 12:37:46 -08001746XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001747{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001748 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001749
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001750 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001751 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001752 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1753 return _errorID;
1754 }
1755
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001757 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001759 if ( filelength == -1L ) {
1760 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1761 return _errorID;
1762 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001763
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001764 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001766 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001769
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 _charBuffer = new char[size+1];
1771 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( read != size ) {
1773 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001776
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001778
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 if ( !p || !*p ) {
1783 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001786
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1788 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001789}
1790
1791
Lee Thomason2fa81722012-11-09 12:37:46 -08001792XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001793{
Dmitry-Me01578db2014-08-19 10:18:48 +04001794 FILE* fp = callfopen( filename, "w" );
1795 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 }
1799 SaveFile(fp, compact);
1800 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001802}
1803
1804
Lee Thomason2fa81722012-11-09 12:37:46 -08001805XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 XMLPrinter stream( fp, compact );
1808 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810}
1811
Lee Thomason1ff38e02012-02-14 18:18:16 -08001812
Lee Thomason2fa81722012-11-09 12:37:46 -08001813XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001814{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001815 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001816 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001817
Lee Thomason82d32002014-02-21 22:47:18 -08001818 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
1822 if ( len == (size_t)(-1) ) {
1823 len = strlen( p );
1824 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 _charBuffer = new char[ len+1 ];
1826 memcpy( _charBuffer, p, len );
1827 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001828
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
Thomas Roß1470edc2013-05-10 15:44:12 +02001836 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001837 ParseDeep( _charBuffer+delta, 0 );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001838 if (_errorID) {
1839 // clean up now essentially dangling memory.
1840 // and the parse fail can put objects in the
1841 // pools that are dead and inaccessible.
1842 DeleteChildren();
1843 _elementPool.Clear();
1844 _attributePool.Clear();
1845 _textPool.Clear();
1846 _commentPool.Clear();
1847 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001849}
1850
1851
PKEuS1c5f99e2013-07-06 11:28:39 +02001852void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001853{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 XMLPrinter stdStreamer( stdout );
1855 if ( !streamer ) {
1856 streamer = &stdStreamer;
1857 }
1858 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001859}
1860
1861
Lee Thomason2fa81722012-11-09 12:37:46 -08001862void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001863{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001864 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 _errorID = error;
1866 _errorStr1 = str1;
1867 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001868}
1869
Lee Thomason331596e2014-09-11 14:56:43 -07001870const char* XMLDocument::ErrorName() const
1871{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001872 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001873 return _errorNames[_errorID];
1874}
Lee Thomason5cae8972012-01-24 18:03:07 -08001875
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001876void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001877{
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 static const int LEN = 20;
1880 char buf1[LEN] = { 0 };
1881 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001882
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 if ( _errorStr1 ) {
1884 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 if ( _errorStr2 ) {
1887 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001889
Lee Thomason331596e2014-09-11 14:56:43 -07001890 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1891 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001893}
1894
1895
PKEuS1bfb9542013-08-04 13:51:17 +02001896XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 _elementJustOpened( false ),
1898 _firstElement( true ),
1899 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001900 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 _textDepth( -1 ),
1902 _processEntities( true ),
1903 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 _entityFlag[i] = false;
1907 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 }
1909 for( int i=0; i<NUM_ENTITIES; ++i ) {
1910 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1911 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 }
1914 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 _restrictedEntityFlag[(int)'&'] = true;
1916 _restrictedEntityFlag[(int)'<'] = true;
1917 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1918 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001919}
1920
1921
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001922void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001923{
1924 va_list va;
1925 va_start( va, format );
1926
Lee Thomason624d43f2012-10-12 10:58:48 -07001927 if ( _fp ) {
1928 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 }
1930 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001931#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001932 #if defined(WINCE)
1933 int len = 512;
1934 do {
1935 len = len*2;
1936 char* str = new char[len]();
1937 len = _vsnprintf(str, len, format, va);
1938 delete[] str;
1939 }while (len < 0);
1940 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001941 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001942 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943#else
1944 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001945#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 // Close out and re-start the va-args
1947 va_end( va );
1948 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001949 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1950#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001951 #if defined(WINCE)
1952 _vsnprintf( p, len+1, format, va );
1953 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001954 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001955 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001956#else
1957 vsnprintf( p, len+1, format, va );
1958#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001960 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001961}
1962
1963
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001964void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001965{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 for( int i=0; i<depth; ++i ) {
1967 Print( " " );
1968 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001969}
1970
1971
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001972void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 // Look for runs of bytes between entities to print.
1975 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001977
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 while ( *q ) {
1980 // Remember, char is sometimes signed. (How many times has that bitten me?)
1981 if ( *q > 0 && *q < ENTITY_RANGE ) {
1982 // Check for entities. If one is found, flush
1983 // the stream up until the entity, write the
1984 // entity, and keep looking.
1985 if ( flag[(unsigned)(*q)] ) {
1986 while ( p < q ) {
1987 Print( "%c", *p );
1988 ++p;
1989 }
1990 for( int i=0; i<NUM_ENTITIES; ++i ) {
1991 if ( entities[i].value == *q ) {
1992 Print( "&%s;", entities[i].pattern );
1993 break;
1994 }
1995 }
1996 ++p;
1997 }
1998 }
1999 ++q;
2000 }
2001 }
2002 // Flush the remaining string. This will be the entire
2003 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 Print( "%s", p );
2006 }
Lee Thomason857b8682012-01-25 17:50:25 -08002007}
2008
U-Stream\Leeae25a442012-02-17 17:48:16 -08002009
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002010void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002013 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 -07002014 Print( "%s", bom );
2015 }
2016 if ( writeDec ) {
2017 PushDeclaration( "xml version=\"1.0\"" );
2018 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002019}
2020
2021
Uli Kusterer593a33d2014-02-01 12:48:51 +01002022void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002023{
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 SealElement();
2026 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002028
Uli Kusterer593a33d2014-02-01 12:48:51 +01002029 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002031 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002032 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002035
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 _elementJustOpened = true;
2038 _firstElement = false;
2039 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002044{
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 Print( " %s=\"", name );
2047 PrintString( value, false );
2048 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002049}
2050
2051
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002052void XMLPrinter::PushAttribute( const char* name, int v )
2053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 char buf[BUF_SIZE];
2055 XMLUtil::ToStr( v, buf, BUF_SIZE );
2056 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002057}
2058
2059
2060void XMLPrinter::PushAttribute( const char* name, unsigned v )
2061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 char buf[BUF_SIZE];
2063 XMLUtil::ToStr( v, buf, BUF_SIZE );
2064 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002065}
2066
2067
2068void XMLPrinter::PushAttribute( const char* name, bool v )
2069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 char buf[BUF_SIZE];
2071 XMLUtil::ToStr( v, buf, BUF_SIZE );
2072 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002073}
2074
2075
2076void XMLPrinter::PushAttribute( const char* name, double v )
2077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 char buf[BUF_SIZE];
2079 XMLUtil::ToStr( v, buf, BUF_SIZE );
2080 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002081}
2082
2083
Uli Kustererca412e82014-02-01 13:35:05 +01002084void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002085{
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 --_depth;
2087 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002088
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 Print( "/>" );
2091 }
2092 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002093 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 }
2097 Print( "</%s>", name );
2098 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002099
Lee Thomason624d43f2012-10-12 10:58:48 -07002100 if ( _textDepth == _depth ) {
2101 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 }
Uli Kustererca412e82014-02-01 13:35:05 +01002103 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 Print( "\n" );
2105 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002106 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002107}
2108
2109
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002110void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002111{
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002114}
2115
2116
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002117void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002118{
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002120
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 SealElement();
2123 }
2124 if ( cdata ) {
2125 Print( "<![CDATA[" );
2126 Print( "%s", text );
2127 Print( "]]>" );
2128 }
2129 else {
2130 PrintString( text, true );
2131 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002132}
2133
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002134void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 char buf[BUF_SIZE];
2137 XMLUtil::ToStr( value, buf, BUF_SIZE );
2138 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002139}
2140
2141
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002142void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 char buf[BUF_SIZE];
2145 XMLUtil::ToStr( value, buf, BUF_SIZE );
2146 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002147}
2148
2149
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002150void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 char buf[BUF_SIZE];
2153 XMLUtil::ToStr( value, buf, BUF_SIZE );
2154 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002155}
2156
2157
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002158void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 char buf[BUF_SIZE];
2161 XMLUtil::ToStr( value, buf, BUF_SIZE );
2162 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002163}
2164
2165
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002166void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 char buf[BUF_SIZE];
2169 XMLUtil::ToStr( value, buf, BUF_SIZE );
2170 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002171}
2172
Lee Thomason5cae8972012-01-24 18:03:07 -08002173
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002174void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002175{
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 SealElement();
2178 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002185}
Lee Thomason751da522012-02-10 08:50:51 -08002186
2187
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002188void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189{
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 SealElement();
2192 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002199}
2200
2201
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002202void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002203{
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 SealElement();
2206 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002209 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002213}
2214
2215
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002216bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002217{
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 if ( doc.HasBOM() ) {
2220 PushHeader( true, false );
2221 }
2222 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002223}
2224
2225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002227{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002228 const XMLElement* parentElem = element.Parent()->ToElement();
2229 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2230 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 while ( attribute ) {
2232 PushAttribute( attribute->Name(), attribute->Value() );
2233 attribute = attribute->Next();
2234 }
2235 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002236}
2237
2238
Uli Kustererca412e82014-02-01 13:35:05 +01002239bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002240{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002241 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002243}
2244
2245
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002246bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 PushText( text.Value(), text.CData() );
2249 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002250}
2251
2252
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002253bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 PushComment( comment.Value() );
2256 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002257}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002258
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002259bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 PushDeclaration( declaration.Value() );
2262 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002263}
2264
2265
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002266bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002267{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 PushUnknown( unknown.Value() );
2269 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002270}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002271
Lee Thomason685b8952012-11-12 13:00:06 -08002272} // namespace tinyxml2
2273