blob: 4956a0583849075047c3307a0e7b001a8bb53baa [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.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# 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
73void StrPair::Reset()
74{
Lee Thomason120b3a62012-10-12 10:06:59 -070075 if ( _flags & NEEDS_DELETE ) {
76 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070077 }
Lee Thomason120b3a62012-10-12 10:06:59 -070078 _flags = 0;
79 _start = 0;
80 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081}
82
83
84void StrPair::SetStr( const char* str, int flags )
85{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070086 Reset();
87 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -070088 _start = new char[ len+1 ];
89 memcpy( _start, str, len+1 );
90 _end = _start + len;
91 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080092}
93
94
95char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
96{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070097 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080098
Dmitry-Meec19a0e2014-08-25 11:05:55 +040099 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 char endChar = *endTag;
101 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800102
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700103 // Inner loop of text parsing.
104 while ( *p ) {
105 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
106 Set( start, p, strFlags );
107 return p + length;
108 }
109 ++p;
110 }
111 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800112}
113
114
115char* StrPair::ParseName( char* p )
116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700117 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 if ( !start || !(*start) ) {
120 return 0;
121 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800122
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200123 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700124 ++p;
125 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700127 if ( p > start ) {
128 Set( start, p, 0 );
129 return p;
130 }
131 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800132}
133
134
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700135void StrPair::CollapseWhitespace()
136{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400137 // Adjusting _start would cause undefined behavior on delete[]
138 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700140 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700141
Lee Thomason120b3a62012-10-12 10:06:59 -0700142 if ( _start && *_start ) {
143 char* p = _start; // the read pointer
144 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700145
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700146 while( *p ) {
147 if ( XMLUtil::IsWhiteSpace( *p )) {
148 p = XMLUtil::SkipWhiteSpace( p );
149 if ( *p == 0 ) {
150 break; // don't write to q; this trims the trailing space.
151 }
152 *q = ' ';
153 ++q;
154 }
155 *q = *p;
156 ++q;
157 ++p;
158 }
159 *q = 0;
160 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161}
162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163
Lee Thomasone4422302012-01-20 17:59:50 -0800164const char* StrPair::GetStr()
165{
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 if ( _flags & NEEDS_FLUSH ) {
167 *_end = 0;
168 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800169
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags ) {
171 char* p = _start; // the read pointer
172 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800173
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 while( p < _end ) {
175 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700176 // CR-LF pair becomes LF
177 // CR alone becomes LF
178 // LF-CR becomes LF
179 if ( *(p+1) == LF ) {
180 p += 2;
181 }
182 else {
183 ++p;
184 }
185 *q++ = LF;
186 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700187 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700188 if ( *(p+1) == CR ) {
189 p += 2;
190 }
191 else {
192 ++p;
193 }
194 *q++ = LF;
195 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700196 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // Entities handled by tinyXML2:
198 // - special entities in the entity table [in/out]
199 // - numeric character reference [in]
200 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400203 const int buflen = 10;
204 char buf[buflen] = { 0 };
205 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400207 TIXMLASSERT( 0 <= len && len <= buflen );
208 TIXMLASSERT( q + len <= p );
209 memcpy( q, buf, len );
210 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 }
212 else {
213 int i=0;
214 for(; i<NUM_ENTITIES; ++i ) {
215 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
216 && *(p+entities[i].length+1) == ';' ) {
217 // Found an entity convert;
218 *q = entities[i].value;
219 ++q;
220 p += entities[i].length + 2;
221 break;
222 }
223 }
224 if ( i == NUM_ENTITIES ) {
225 // fixme: treat as error?
226 ++p;
227 ++q;
228 }
229 }
230 }
231 else {
232 *q = *p;
233 ++p;
234 ++q;
235 }
236 }
237 *q = 0;
238 }
239 // The loop below has plenty going on, and this
240 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 CollapseWhitespace();
243 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700244 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800247}
248
Lee Thomason2c85a712012-01-31 08:24:24 -0800249
Lee Thomasone4422302012-01-20 17:59:50 -0800250
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800251
Lee Thomason56bdd022012-02-09 18:16:58 -0800252// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800253
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800254const char* XMLUtil::ReadBOM( const char* p, bool* bom )
255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 *bom = false;
257 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
258 // Check for BOM:
259 if ( *(pu+0) == TIXML_UTF_LEAD_0
260 && *(pu+1) == TIXML_UTF_LEAD_1
261 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
262 *bom = true;
263 p += 3;
264 }
265 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266}
267
268
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800269void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 const unsigned long BYTE_MASK = 0xBF;
272 const unsigned long BYTE_MARK = 0x80;
273 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800274
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 if (input < 0x80) {
276 *length = 1;
277 }
278 else if ( input < 0x800 ) {
279 *length = 2;
280 }
281 else if ( input < 0x10000 ) {
282 *length = 3;
283 }
284 else if ( input < 0x200000 ) {
285 *length = 4;
286 }
287 else {
288 *length = 0; // This code won't covert this correctly anyway.
289 return;
290 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 // Scary scary fall throughs.
295 switch (*length) {
296 case 4:
297 --output;
298 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
299 input >>= 6;
300 case 3:
301 --output;
302 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
303 input >>= 6;
304 case 2:
305 --output;
306 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
307 input >>= 6;
308 case 1:
309 --output;
310 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100311 default:
312 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800314}
315
316
317const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 // Presume an entity, and pull it out.
320 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 if ( *(p+1) == '#' && *(p+2) ) {
323 unsigned long ucs = 0;
324 ptrdiff_t delta = 0;
325 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800326
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 if ( *(p+2) == 'x' ) {
328 // Hexadecimal.
329 if ( !*(p+3) ) {
330 return 0;
331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 const char* q = p+3;
334 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800335
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 if ( !q || !*q ) {
337 return 0;
338 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 delta = q-p;
341 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 while ( *q != 'x' ) {
344 if ( *q >= '0' && *q <= '9' ) {
345 ucs += mult * (*q - '0');
346 }
347 else if ( *q >= 'a' && *q <= 'f' ) {
348 ucs += mult * (*q - 'a' + 10);
349 }
350 else if ( *q >= 'A' && *q <= 'F' ) {
351 ucs += mult * (*q - 'A' + 10 );
352 }
353 else {
354 return 0;
355 }
356 mult *= 16;
357 --q;
358 }
359 }
360 else {
361 // Decimal.
362 if ( !*(p+2) ) {
363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 const char* q = p+2;
367 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( !q || !*q ) {
370 return 0;
371 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != '#' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else {
381 return 0;
382 }
383 mult *= 10;
384 --q;
385 }
386 }
387 // convert the UCS to UTF-8
388 ConvertUTF32ToUTF8( ucs, value, length );
389 return p + delta + 1;
390 }
391 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800393
394
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700395void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700398}
399
400
401void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700404}
405
406
407void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700410}
411
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800412/*
413 ToStr() of a number is a very tricky topic.
414 https://github.com/leethomason/tinyxml2/issues/106
415*/
Lee Thomason21be8822012-07-15 17:27:22 -0700416void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
417{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800418 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
423{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800424 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428bool XMLUtil::ToInt( const char* str, int* value )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
431 return true;
432 }
433 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
439 return true;
440 }
441 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700442}
443
444bool XMLUtil::ToBool( const char* str, bool* value )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 int ival = 0;
447 if ( ToInt( str, &ival )) {
448 *value = (ival==0) ? false : true;
449 return true;
450 }
451 if ( StringEqual( str, "true" ) ) {
452 *value = true;
453 return true;
454 }
455 else if ( StringEqual( str, "false" ) ) {
456 *value = false;
457 return true;
458 }
459 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700460}
461
462
463bool XMLUtil::ToFloat( const char* str, float* value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToDouble( const char* str, double* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
474 return true;
475 }
476 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
numatrumpet00336842014-09-08 16:36:28 +0900479const char* XMLUtil::ToErrorName( const XMLError errorID )
numatrumpetbb5ffac2014-09-06 22:56:46 +0900480{
numatrumpetbb5ffac2014-09-06 22:56:46 +0900481 return ErrorNames[errorID];
numatrumpetbb5ffac2014-09-06 22:56:46 +0900482}
Lee Thomason21be8822012-07-15 17:27:22 -0700483
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700484char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 XMLNode* returnNode = 0;
487 char* start = p;
488 p = XMLUtil::SkipWhiteSpace( p );
489 if( !p || !*p ) {
490 return p;
491 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800492
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800494 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 static const char* xmlHeader = { "<?" };
496 static const char* commentHeader = { "<!--" };
497 static const char* dtdHeader = { "<!" };
498 static const char* cdataHeader = { "<![CDATA[" };
499 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 static const int xmlHeaderLen = 2;
502 static const int commentHeaderLen = 4;
503 static const int dtdHeaderLen = 2;
504 static const int cdataHeaderLen = 9;
505 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800506
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800507#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800508#pragma warning ( push )
509#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800510#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700511 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
512 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800513#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800514#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800515#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700517 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
518 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 p += xmlHeaderLen;
520 }
521 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700522 returnNode = new (_commentPool.Alloc()) XMLComment( this );
523 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 p += commentHeaderLen;
525 }
526 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700527 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700529 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 p += cdataHeaderLen;
531 text->SetCData( true );
532 }
533 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700534 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
535 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 p += dtdHeaderLen;
537 }
538 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700539 returnNode = new (_elementPool.Alloc()) XMLElement( this );
540 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 p += elementHeaderLen;
542 }
543 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_textPool.Alloc()) XMLText( this );
545 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p = start; // Back it up, all the text counts.
547 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800548
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 *node = returnNode;
550 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800551}
552
553
Lee Thomason751da522012-02-10 08:50:51 -0800554bool XMLDocument::Accept( XMLVisitor* visitor ) const
555{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 if ( visitor->VisitEnter( *this ) ) {
557 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
558 if ( !node->Accept( visitor ) ) {
559 break;
560 }
561 }
562 }
563 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800564}
Lee Thomason56bdd022012-02-09 18:16:58 -0800565
566
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800567// --------- XMLNode ----------- //
568
569XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 _document( doc ),
571 _parent( 0 ),
572 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200573 _prev( 0 ), _next( 0 ),
574 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800575{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576}
577
578
579XMLNode::~XMLNode()
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 if ( _parent ) {
583 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800585}
586
Michael Daumling21626882013-10-22 17:03:37 +0200587const char* XMLNode::Value() const
588{
589 return _value.GetStr();
590}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800591
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800592void XMLNode::SetValue( const char* str, bool staticMem )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 }
597 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700598 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800600}
601
602
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800603void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800604{
Lee Thomason624d43f2012-10-12 10:58:48 -0700605 while( _firstChild ) {
606 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700608
Dmitry-Mee3225b12014-09-03 11:03:11 +0400609 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700611 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800612}
613
614
615void XMLNode::Unlink( XMLNode* child )
616{
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 if ( child == _firstChild ) {
618 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( child == _lastChild ) {
621 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomasond923c672012-01-23 08:44:25 -0800623
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 if ( child->_prev ) {
625 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 if ( child->_next ) {
628 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700630 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800631}
632
633
U-Stream\Leeae25a442012-02-17 17:48:16 -0800634void XMLNode::DeleteChild( XMLNode* node )
635{
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400637 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800638}
639
640
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
642{
Michael Daumlinged523282013-10-23 07:47:29 +0200643 if (addThis->_document != _document)
644 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700645
Michael Daumlinged523282013-10-23 07:47:29 +0200646 if (addThis->_parent)
647 addThis->_parent->Unlink( addThis );
648 else
649 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700650
Lee Thomason624d43f2012-10-12 10:58:48 -0700651 if ( _lastChild ) {
652 TIXMLASSERT( _firstChild );
653 TIXMLASSERT( _lastChild->_next == 0 );
654 _lastChild->_next = addThis;
655 addThis->_prev = _lastChild;
656 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 }
660 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 TIXMLASSERT( _firstChild == 0 );
662 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Lee Thomason624d43f2012-10-12 10:58:48 -0700664 addThis->_prev = 0;
665 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800669}
670
671
Lee Thomason1ff38e02012-02-14 18:18:16 -0800672XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
673{
Michael Daumlinged523282013-10-23 07:47:29 +0200674 if (addThis->_document != _document)
675 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700676
Michael Daumlinged523282013-10-23 07:47:29 +0200677 if (addThis->_parent)
678 addThis->_parent->Unlink( addThis );
679 else
680 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 if ( _firstChild ) {
683 TIXMLASSERT( _lastChild );
684 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 _firstChild->_prev = addThis;
687 addThis->_next = _firstChild;
688 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
692 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 TIXMLASSERT( _lastChild == 0 );
694 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_prev = 0;
697 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200700 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701}
702
703
704XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
705{
Michael Daumlinged523282013-10-23 07:47:29 +0200706 if (addThis->_document != _document)
707 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 return 0;
713 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 // The last node or the only node.
717 return InsertEndChild( addThis );
718 }
Michael Daumlinged523282013-10-23 07:47:29 +0200719 if (addThis->_parent)
720 addThis->_parent->Unlink( addThis );
721 else
722 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_prev = afterThis;
724 addThis->_next = afterThis->_next;
725 afterThis->_next->_prev = addThis;
726 afterThis->_next = addThis;
727 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729}
730
731
732
733
Lee Thomason56bdd022012-02-09 18:16:58 -0800734const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800735{
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 XMLElement* element = node->ToElement();
738 if ( element ) {
739 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
740 return element;
741 }
742 }
743 }
744 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800745}
746
747
Lee Thomason56bdd022012-02-09 18:16:58 -0800748const XMLElement* XMLNode::LastChildElement( const char* value ) const
749{
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 XMLElement* element = node->ToElement();
752 if ( element ) {
753 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
754 return element;
755 }
756 }
757 }
758 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800759}
760
761
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800762const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
763{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400764 for( XMLNode* node=this->_next; node; node = node->_next ) {
765 const XMLElement* element = node->ToElement();
766 if ( element
767 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
768 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 }
771 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772}
773
774
775const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
776{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400777 for( XMLNode* node=_prev; node; node = node->_prev ) {
778 const XMLElement* element = node->ToElement();
779 if ( element
780 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
781 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
783 }
784 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800785}
786
787
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800788char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800789{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 // This is a recursive method, but thinking about it "at the current level"
791 // it is a pretty simple flat list:
792 // <foo/>
793 // <!-- comment -->
794 //
795 // With a special case:
796 // <foo>
797 // </foo>
798 // <!-- comment -->
799 //
800 // Where the closing element (/foo) *must* be the next thing after the opening
801 // element, and the names must match. BUT the tricky bit is that the closing
802 // element will be read by the child.
803 //
804 // 'endTag' is the end tag for this node, it is returned by a call to a child.
805 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800806
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 while( p && *p ) {
808 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 if ( p == 0 || node == 0 ) {
812 break;
813 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800814
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 StrPair endTag;
816 p = node->ParseDeep( p, &endTag );
817 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400818 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 if ( !_document->Error() ) {
821 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 break;
824 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800825
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400826 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400828 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800832 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400833 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 return p;
835 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800836
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 // Handle an end tag returned to this level.
838 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 if ( ele ) {
840 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 p = 0;
843 }
844 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700845 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 p = 0;
847 }
848 else if ( !endTag.Empty() ) {
849 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 p = 0;
852 }
853 }
854 }
855 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400856 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 node = 0;
858 }
859 if ( node ) {
860 this->InsertEndChild( node );
861 }
862 }
863 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800864}
865
Dmitry-Mee3225b12014-09-03 11:03:11 +0400866void XMLNode::DeleteNode( XMLNode* node )
867{
868 if ( node == 0 ) {
869 return;
870 }
871 MemPool* pool = node->_memPool;
872 node->~XMLNode();
873 pool->Free( node );
874}
875
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800877char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 const char* start = p;
880 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 return p;
886 }
887 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
889 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 flags |= StrPair::COLLAPSE_WHITESPACE;
891 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
897 if ( p && *p ) {
898 return p-1;
899 }
900 }
901 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800902}
903
904
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700908 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 }
910 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
911 text->SetCData( this->CData() );
912 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800913}
914
915
916bool XMLText::ShallowEqual( const XMLNode* compare ) const
917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800919}
920
921
Lee Thomason56bdd022012-02-09 18:16:58 -0800922bool XMLText::Accept( XMLVisitor* visitor ) const
923{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800925}
926
927
Lee Thomason3f57d272012-01-11 15:30:03 -0800928// --------- XMLComment ---------- //
929
Lee Thomasone4422302012-01-20 17:59:50 -0800930XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800931{
932}
933
934
Lee Thomasonce0763e2012-01-11 15:43:54 -0800935XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800936{
Lee Thomason3f57d272012-01-11 15:30:03 -0800937}
938
939
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800940char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 // Comment parses as text.
943 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 }
948 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800949}
950
951
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
958 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959}
960
961
962bool XMLComment::ShallowEqual( const XMLNode* compare ) const
963{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400964 const XMLComment* comment = compare->ToComment();
965 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800966}
967
968
Lee Thomason751da522012-02-10 08:50:51 -0800969bool XMLComment::Accept( XMLVisitor* visitor ) const
970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800972}
Lee Thomason56bdd022012-02-09 18:16:58 -0800973
974
Lee Thomason50f97b22012-02-11 16:33:40 -0800975// --------- XMLDeclaration ---------- //
976
977XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
978{
979}
980
981
982XMLDeclaration::~XMLDeclaration()
983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800985}
986
987
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800988char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 // Declaration parses as text.
991 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
996 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800997}
998
999
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001000XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001003 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1006 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
1010bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1011{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001012 const XMLDeclaration* declaration = compare->ToDeclaration();
1013 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001014}
1015
1016
1017
Lee Thomason50f97b22012-02-11 16:33:40 -08001018bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001021}
1022
1023// --------- XMLUnknown ---------- //
1024
1025XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1026{
1027}
1028
1029
1030XMLUnknown::~XMLUnknown()
1031{
1032}
1033
1034
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001035char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 // Unknown parses as text.
1038 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001039
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001045}
1046
1047
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001048XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001051 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
1053 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1054 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055}
1056
1057
1058bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1059{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001060 const XMLUnknown* unknown = compare->ToUnknown();
1061 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001062}
1063
1064
Lee Thomason50f97b22012-02-11 16:33:40 -08001065bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1066{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001070// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001071
1072const char* XMLAttribute::Name() const
1073{
1074 return _name.GetStr();
1075}
1076
1077const char* XMLAttribute::Value() const
1078{
1079 return _value.GetStr();
1080}
1081
Lee Thomason6f381b72012-03-02 12:59:39 -08001082char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( !p || !*p ) {
1087 return 0;
1088 }
Lee Thomason22aead12012-01-23 13:29:35 -08001089
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 // Skip white space before =
1091 p = XMLUtil::SkipWhiteSpace( p );
1092 if ( !p || *p != '=' ) {
1093 return 0;
1094 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001095
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 ++p; // move up to opening quote
1097 p = XMLUtil::SkipWhiteSpace( p );
1098 if ( *p != '\"' && *p != '\'' ) {
1099 return 0;
1100 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001101
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 char endTag[2] = { *p, 0 };
1103 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001104
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001107}
1108
1109
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001110void XMLAttribute::SetName( const char* n )
1111{
Lee Thomason624d43f2012-10-12 10:58:48 -07001112 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001113}
1114
1115
Lee Thomason2fa81722012-11-09 12:37:46 -08001116XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( XMLUtil::ToInt( Value(), value )) {
1119 return XML_NO_ERROR;
1120 }
1121 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122}
1123
1124
Lee Thomason2fa81722012-11-09 12:37:46 -08001125XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 if ( XMLUtil::ToUnsigned( Value(), value )) {
1128 return XML_NO_ERROR;
1129 }
1130 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131}
1132
1133
Lee Thomason2fa81722012-11-09 12:37:46 -08001134XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( XMLUtil::ToBool( Value(), value )) {
1137 return XML_NO_ERROR;
1138 }
1139 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140}
1141
1142
Lee Thomason2fa81722012-11-09 12:37:46 -08001143XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 if ( XMLUtil::ToFloat( Value(), value )) {
1146 return XML_NO_ERROR;
1147 }
1148 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001149}
1150
1151
Lee Thomason2fa81722012-11-09 12:37:46 -08001152XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 if ( XMLUtil::ToDouble( Value(), value )) {
1155 return XML_NO_ERROR;
1156 }
1157 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158}
1159
1160
1161void XMLAttribute::SetAttribute( const char* v )
1162{
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001164}
1165
1166
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167void XMLAttribute::SetAttribute( int v )
1168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 char buf[BUF_SIZE];
1170 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001171 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001173
1174
1175void XMLAttribute::SetAttribute( unsigned v )
1176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 char buf[BUF_SIZE];
1178 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001180}
1181
1182
1183void XMLAttribute::SetAttribute( bool v )
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 char buf[BUF_SIZE];
1186 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001188}
1189
1190void XMLAttribute::SetAttribute( double 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 Thomason1a1d4a72012-02-15 09:09:25 -08001195}
1196
1197void XMLAttribute::SetAttribute( float v )
1198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 char buf[BUF_SIZE];
1200 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001202}
1203
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001204
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205// --------- XMLElement ---------- //
1206XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 _closingType( 0 ),
1208 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001209{
1210}
1211
1212
1213XMLElement::~XMLElement()
1214{
Lee Thomason624d43f2012-10-12 10:58:48 -07001215 while( _rootAttribute ) {
1216 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001217 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001218 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001220}
1221
1222
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223XMLAttribute* XMLElement::FindAttribute( const char* name )
1224{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001225 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1227 return a;
1228 }
1229 }
1230 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001231}
1232
1233
1234const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1235{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001236 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1238 return a;
1239 }
1240 }
1241 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001242}
1243
1244
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001245const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 const XMLAttribute* a = FindAttribute( name );
1248 if ( !a ) {
1249 return 0;
1250 }
1251 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1252 return a->Value();
1253 }
1254 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001255}
1256
1257
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001258const char* XMLElement::GetText() const
1259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( FirstChild() && FirstChild()->ToText() ) {
1261 return FirstChild()->ToText()->Value();
1262 }
1263 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001264}
1265
1266
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001267void XMLElement::SetText( const char* inText )
1268{
Uli Kusterer869bb592014-01-21 01:36:16 +01001269 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001270 FirstChild()->SetValue( inText );
1271 else {
1272 XMLText* theText = GetDocument()->NewText( inText );
1273 InsertFirstChild( theText );
1274 }
1275}
1276
Lee Thomason5bb2d802014-01-24 10:42:57 -08001277
1278void XMLElement::SetText( int v )
1279{
1280 char buf[BUF_SIZE];
1281 XMLUtil::ToStr( v, buf, BUF_SIZE );
1282 SetText( buf );
1283}
1284
1285
1286void XMLElement::SetText( unsigned v )
1287{
1288 char buf[BUF_SIZE];
1289 XMLUtil::ToStr( v, buf, BUF_SIZE );
1290 SetText( buf );
1291}
1292
1293
1294void XMLElement::SetText( bool v )
1295{
1296 char buf[BUF_SIZE];
1297 XMLUtil::ToStr( v, buf, BUF_SIZE );
1298 SetText( buf );
1299}
1300
1301
1302void XMLElement::SetText( float v )
1303{
1304 char buf[BUF_SIZE];
1305 XMLUtil::ToStr( v, buf, BUF_SIZE );
1306 SetText( buf );
1307}
1308
1309
1310void XMLElement::SetText( double v )
1311{
1312 char buf[BUF_SIZE];
1313 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314 SetText( buf );
1315}
1316
1317
MortenMacFly4ee49f12013-01-14 20:03:14 +01001318XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 if ( FirstChild() && FirstChild()->ToText() ) {
1321 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001322 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 return XML_SUCCESS;
1324 }
1325 return XML_CAN_NOT_CONVERT_TEXT;
1326 }
1327 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001328}
1329
1330
MortenMacFly4ee49f12013-01-14 20:03:14 +01001331XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 if ( FirstChild() && FirstChild()->ToText() ) {
1334 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001335 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 return XML_SUCCESS;
1337 }
1338 return XML_CAN_NOT_CONVERT_TEXT;
1339 }
1340 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001341}
1342
1343
MortenMacFly4ee49f12013-01-14 20:03:14 +01001344XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 if ( FirstChild() && FirstChild()->ToText() ) {
1347 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 return XML_SUCCESS;
1350 }
1351 return XML_CAN_NOT_CONVERT_TEXT;
1352 }
1353 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001354}
1355
1356
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 if ( FirstChild() && FirstChild()->ToText() ) {
1360 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 return XML_SUCCESS;
1363 }
1364 return XML_CAN_NOT_CONVERT_TEXT;
1365 }
1366 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001367}
1368
1369
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 if ( FirstChild() && FirstChild()->ToText() ) {
1373 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 return XML_SUCCESS;
1376 }
1377 return XML_CAN_NOT_CONVERT_TEXT;
1378 }
1379 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001380}
1381
1382
1383
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001384XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1385{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 XMLAttribute* last = 0;
1387 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001390 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1392 break;
1393 }
1394 }
1395 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1397 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 }
1401 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001402 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001405 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 }
1407 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001408}
1409
1410
U-Stream\Leeae25a442012-02-17 17:48:16 -08001411void XMLElement::DeleteAttribute( const char* name )
1412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1416 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001422 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 break;
1424 }
1425 prev = a;
1426 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001427}
1428
1429
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001430char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 const char* start = p;
1433 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001434
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 // Read the attributes.
1436 while( p ) {
1437 p = XMLUtil::SkipWhiteSpace( p );
1438 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 return 0;
1441 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001442
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001444 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1446 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001447 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001448
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001451 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 return 0;
1454 }
1455 // There is a minor bug here: if the attribute in the source xml
1456 // document is duplicated, it will not be detected and the
1457 // attribute will be doubly added. However, tracking the 'prevAttribute'
1458 // avoids re-scanning the attribute list. Preferring performance for
1459 // now, may reconsider in the future.
1460 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 }
1463 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 }
1466 prevAttribute = attrib;
1467 }
1468 // end of the tag
1469 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 return p+2; // done; sealed element.
1472 }
1473 // end of the tag
1474 else if ( *p == '>' ) {
1475 ++p;
1476 break;
1477 }
1478 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 return 0;
1481 }
1482 }
1483 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001484}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001485
Dmitry-Mee3225b12014-09-03 11:03:11 +04001486void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1487{
1488 if ( attribute == 0 ) {
1489 return;
1490 }
1491 MemPool* pool = attribute->_memPool;
1492 attribute->~XMLAttribute();
1493 pool->Free( attribute );
1494}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001495
Lee Thomason67d61312012-01-24 16:01:51 -08001496//
1497// <ele></ele>
1498// <ele>foo<b>bar</b></ele>
1499//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001500char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 // Read the element name.
1503 p = XMLUtil::SkipWhiteSpace( p );
1504 if ( !p ) {
1505 return 0;
1506 }
Lee Thomason67d61312012-01-24 16:01:51 -08001507
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 // The closing element is the </element> form. It is
1509 // parsed just like a regular element then deleted from
1510 // the DOM.
1511 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 ++p;
1514 }
Lee Thomason67d61312012-01-24 16:01:51 -08001515
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 p = _value.ParseName( p );
1517 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 return 0;
1519 }
Lee Thomason67d61312012-01-24 16:01:51 -08001520
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 return p;
1524 }
Lee Thomason67d61312012-01-24 16:01:51 -08001525
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 p = XMLNode::ParseDeep( p, strPair );
1527 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001528}
1529
1530
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001531
1532XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1538 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1539 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1540 }
1541 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001542}
1543
1544
1545bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 const XMLElement* other = compare->ToElement();
1548 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001549
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 const XMLAttribute* a=FirstAttribute();
1551 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001552
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 while ( a && b ) {
1554 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1555 return false;
1556 }
1557 a = a->Next();
1558 b = b->Next();
1559 }
1560 if ( a || b ) {
1561 // different count
1562 return false;
1563 }
1564 return true;
1565 }
1566 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001567}
1568
1569
Lee Thomason751da522012-02-10 08:50:51 -08001570bool XMLElement::Accept( XMLVisitor* visitor ) const
1571{
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1574 if ( !node->Accept( visitor ) ) {
1575 break;
1576 }
1577 }
1578 }
1579 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001580}
Lee Thomason56bdd022012-02-09 18:16:58 -08001581
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomason3f57d272012-01-11 15:30:03 -08001583// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001584XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001586 _writeBOM( false ),
1587 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001588 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001589 _whitespace( whitespace ),
1590 _errorStr1( 0 ),
1591 _errorStr2( 0 ),
1592 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001593{
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001595}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001596
1597
Lee Thomason3f57d272012-01-11 15:30:03 -08001598XMLDocument::~XMLDocument()
1599{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001601 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001602
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001603#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001604 _textPool.Trace( "text" );
1605 _elementPool.Trace( "element" );
1606 _commentPool.Trace( "comment" );
1607 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001608#endif
1609
Lee Thomason5b0a6772012-11-19 13:54:42 -08001610#ifdef DEBUG
1611 if ( Error() == false ) {
1612 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1613 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1614 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1615 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1616 }
1617#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001618}
1619
1620
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001621void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001622{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001623 DeleteChildren();
1624
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 _errorID = XML_NO_ERROR;
1626 _errorStr1 = 0;
1627 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001628
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 delete [] _charBuffer;
1630 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001631}
1632
Lee Thomason3f57d272012-01-11 15:30:03 -08001633
Lee Thomason2c85a712012-01-31 08:24:24 -08001634XMLElement* XMLDocument::NewElement( const char* name )
1635{
Lee Thomason624d43f2012-10-12 10:58:48 -07001636 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1637 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 ele->SetName( name );
1639 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001640}
1641
1642
Lee Thomason1ff38e02012-02-14 18:18:16 -08001643XMLComment* XMLDocument::NewComment( const char* str )
1644{
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1646 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 comment->SetValue( str );
1648 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001649}
1650
1651
1652XMLText* XMLDocument::NewText( const char* str )
1653{
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1655 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 text->SetValue( str );
1657 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001658}
1659
1660
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001661XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1662{
Lee Thomason624d43f2012-10-12 10:58:48 -07001663 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1664 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1666 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001667}
1668
1669
1670XMLUnknown* XMLDocument::NewUnknown( const char* str )
1671{
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1673 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 unk->SetValue( str );
1675 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001676}
1677
Dmitry-Me01578db2014-08-19 10:18:48 +04001678static FILE* callfopen( const char* filepath, const char* mode )
1679{
1680#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1681 FILE* fp = 0;
1682 errno_t err = fopen_s( &fp, filepath, mode );
1683 if ( err ) {
1684 return 0;
1685 }
1686#else
1687 FILE* fp = fopen( filepath, mode );
1688#endif
1689 return fp;
1690}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001691
Lee Thomason2fa81722012-11-09 12:37:46 -08001692XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001693{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001694 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001695 FILE* fp = callfopen( filename, "rb" );
1696 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 }
1700 LoadFile( fp );
1701 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001702 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001703}
1704
1705
Lee Thomason2fa81722012-11-09 12:37:46 -08001706XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001707{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001708 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001709
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001710 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001711 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001712 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1713 return _errorID;
1714 }
1715
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001717 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001719 if ( filelength == -1L ) {
1720 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1721 return _errorID;
1722 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001723
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001724 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001726 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001729
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 _charBuffer = new char[size+1];
1731 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 if ( read != size ) {
1733 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001736
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001738
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 if ( !p || !*p ) {
1743 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001746
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1748 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001749}
1750
1751
Lee Thomason2fa81722012-11-09 12:37:46 -08001752XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001753{
Dmitry-Me01578db2014-08-19 10:18:48 +04001754 FILE* fp = callfopen( filename, "w" );
1755 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 }
1759 SaveFile(fp, compact);
1760 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001762}
1763
1764
Lee Thomason2fa81722012-11-09 12:37:46 -08001765XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 XMLPrinter stream( fp, compact );
1768 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001770}
1771
Lee Thomason1ff38e02012-02-14 18:18:16 -08001772
Lee Thomason2fa81722012-11-09 12:37:46 -08001773XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001774{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001775 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001776 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001777
Lee Thomason82d32002014-02-21 22:47:18 -08001778 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 }
1782 if ( len == (size_t)(-1) ) {
1783 len = strlen( p );
1784 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 _charBuffer = new char[ len+1 ];
1786 memcpy( _charBuffer, p, len );
1787 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001788
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 if ( !p || !*p ) {
1792 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001795
Thomas Roß1470edc2013-05-10 15:44:12 +02001796 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001797 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001799}
1800
1801
PKEuS1c5f99e2013-07-06 11:28:39 +02001802void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001803{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 XMLPrinter stdStreamer( stdout );
1805 if ( !streamer ) {
1806 streamer = &stdStreamer;
1807 }
1808 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001809}
1810
1811
Lee Thomason2fa81722012-11-09 12:37:46 -08001812void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001813{
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 _errorID = error;
1815 _errorStr1 = str1;
1816 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001817}
1818
Lee Thomason5cae8972012-01-24 18:03:07 -08001819
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001820void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001821{
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 static const int LEN = 20;
1824 char buf1[LEN] = { 0 };
1825 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001826
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 if ( _errorStr1 ) {
1828 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 if ( _errorStr2 ) {
1831 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837}
1838
1839
PKEuS1bfb9542013-08-04 13:51:17 +02001840XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 _elementJustOpened( false ),
1842 _firstElement( true ),
1843 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001844 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _textDepth( -1 ),
1846 _processEntities( true ),
1847 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001848{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 _entityFlag[i] = false;
1851 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
1853 for( int i=0; i<NUM_ENTITIES; ++i ) {
1854 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1855 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 }
1858 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _restrictedEntityFlag[(int)'&'] = true;
1860 _restrictedEntityFlag[(int)'<'] = true;
1861 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1862 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001863}
1864
1865
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001866void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001867{
1868 va_list va;
1869 va_start( va, format );
1870
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 if ( _fp ) {
1872 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
1874 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001875#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001876 #if defined(WINCE)
1877 int len = 512;
1878 do {
1879 len = len*2;
1880 char* str = new char[len]();
1881 len = _vsnprintf(str, len, format, va);
1882 delete[] str;
1883 }while (len < 0);
1884 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001885 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001886 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887#else
1888 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001889#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 // Close out and re-start the va-args
1891 va_end( va );
1892 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001893 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1894#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001895 #if defined(WINCE)
1896 _vsnprintf( p, len+1, format, va );
1897 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001898 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001899 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001900#else
1901 vsnprintf( p, len+1, format, va );
1902#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001904 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001905}
1906
1907
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001908void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001909{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 for( int i=0; i<depth; ++i ) {
1911 Print( " " );
1912 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001913}
1914
1915
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001916void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 // Look for runs of bytes between entities to print.
1919 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001921
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 while ( *q ) {
1924 // Remember, char is sometimes signed. (How many times has that bitten me?)
1925 if ( *q > 0 && *q < ENTITY_RANGE ) {
1926 // Check for entities. If one is found, flush
1927 // the stream up until the entity, write the
1928 // entity, and keep looking.
1929 if ( flag[(unsigned)(*q)] ) {
1930 while ( p < q ) {
1931 Print( "%c", *p );
1932 ++p;
1933 }
1934 for( int i=0; i<NUM_ENTITIES; ++i ) {
1935 if ( entities[i].value == *q ) {
1936 Print( "&%s;", entities[i].pattern );
1937 break;
1938 }
1939 }
1940 ++p;
1941 }
1942 }
1943 ++q;
1944 }
1945 }
1946 // Flush the remaining string. This will be the entire
1947 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 Print( "%s", p );
1950 }
Lee Thomason857b8682012-01-25 17:50:25 -08001951}
1952
U-Stream\Leeae25a442012-02-17 17:48:16 -08001953
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001954void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001957 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 -07001958 Print( "%s", bom );
1959 }
1960 if ( writeDec ) {
1961 PushDeclaration( "xml version=\"1.0\"" );
1962 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001963}
1964
1965
Uli Kusterer593a33d2014-02-01 12:48:51 +01001966void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001967{
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 SealElement();
1970 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001972
Uli Kusterer593a33d2014-02-01 12:48:51 +01001973 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001975 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001976 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001979
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 _elementJustOpened = true;
1982 _firstElement = false;
1983 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001984}
1985
1986
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001987void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001988{
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 Print( " %s=\"", name );
1991 PrintString( value, false );
1992 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001993}
1994
1995
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001996void XMLPrinter::PushAttribute( const char* name, int v )
1997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 char buf[BUF_SIZE];
1999 XMLUtil::ToStr( v, buf, BUF_SIZE );
2000 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002001}
2002
2003
2004void XMLPrinter::PushAttribute( const char* name, unsigned v )
2005{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 char buf[BUF_SIZE];
2007 XMLUtil::ToStr( v, buf, BUF_SIZE );
2008 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002009}
2010
2011
2012void XMLPrinter::PushAttribute( const char* name, bool v )
2013{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 char buf[BUF_SIZE];
2015 XMLUtil::ToStr( v, buf, BUF_SIZE );
2016 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002017}
2018
2019
2020void XMLPrinter::PushAttribute( const char* name, double v )
2021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 char buf[BUF_SIZE];
2023 XMLUtil::ToStr( v, buf, BUF_SIZE );
2024 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002025}
2026
2027
Uli Kustererca412e82014-02-01 13:35:05 +01002028void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002029{
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 --_depth;
2031 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002032
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 Print( "/>" );
2035 }
2036 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002037 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 }
2041 Print( "</%s>", name );
2042 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 if ( _textDepth == _depth ) {
2045 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 }
Uli Kustererca412e82014-02-01 13:35:05 +01002047 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 Print( "\n" );
2049 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002051}
2052
2053
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002054void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002055{
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002058}
2059
2060
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002061void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002062{
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002064
Lee Thomason624d43f2012-10-12 10:58:48 -07002065 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 SealElement();
2067 }
2068 if ( cdata ) {
2069 Print( "<![CDATA[" );
2070 Print( "%s", text );
2071 Print( "]]>" );
2072 }
2073 else {
2074 PrintString( text, true );
2075 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002076}
2077
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002078void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 char buf[BUF_SIZE];
2081 XMLUtil::ToStr( value, buf, BUF_SIZE );
2082 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002083}
2084
2085
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002086void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 char buf[BUF_SIZE];
2089 XMLUtil::ToStr( value, buf, BUF_SIZE );
2090 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002091}
2092
2093
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002094void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 char buf[BUF_SIZE];
2097 XMLUtil::ToStr( value, buf, BUF_SIZE );
2098 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002099}
2100
2101
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002102void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 char buf[BUF_SIZE];
2105 XMLUtil::ToStr( value, buf, BUF_SIZE );
2106 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002107}
2108
2109
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002110void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 char buf[BUF_SIZE];
2113 XMLUtil::ToStr( value, buf, BUF_SIZE );
2114 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002115}
2116
Lee Thomason5cae8972012-01-24 18:03:07 -08002117
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002118void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002119{
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 SealElement();
2122 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002129}
Lee Thomason751da522012-02-10 08:50:51 -08002130
2131
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002132void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002133{
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 SealElement();
2136 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002143}
2144
2145
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002146void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147{
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 SealElement();
2150 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002157}
2158
2159
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002160bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002161{
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 if ( doc.HasBOM() ) {
2164 PushHeader( true, false );
2165 }
2166 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002167}
2168
2169
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002170bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002171{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002172 const XMLElement* parentElem = element.Parent()->ToElement();
2173 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2174 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 while ( attribute ) {
2176 PushAttribute( attribute->Name(), attribute->Value() );
2177 attribute = attribute->Next();
2178 }
2179 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002180}
2181
2182
Uli Kustererca412e82014-02-01 13:35:05 +01002183bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002184{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002185 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002187}
2188
2189
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002190bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 PushText( text.Value(), text.CData() );
2193 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002194}
2195
2196
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002197bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 PushComment( comment.Value() );
2200 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002201}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002202
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002203bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 PushDeclaration( declaration.Value() );
2206 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002207}
2208
2209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 PushUnknown( unknown.Value() );
2213 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002214}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002215
Lee Thomason685b8952012-11-12 13:00:06 -08002216} // namespace tinyxml2
2217