blob: fd9ef1686b0568a5c151727c9d2a736179fa5c24 [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
numatrumpetbb5ffac2014-09-06 22:56:46 +0900479std::string XMLUtil::ToErrorName( const XMLError errorID )
480{
481#if __cplusplus > 199711LL
482 return ErrorNames[errorID];
483#else
484 return std::string("Use C++11 or higher to use this function");
485#endif
486}
Lee Thomason21be8822012-07-15 17:27:22 -0700487
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700488char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 XMLNode* returnNode = 0;
491 char* start = p;
492 p = XMLUtil::SkipWhiteSpace( p );
493 if( !p || !*p ) {
494 return p;
495 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800498 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 static const char* xmlHeader = { "<?" };
500 static const char* commentHeader = { "<!--" };
501 static const char* dtdHeader = { "<!" };
502 static const char* cdataHeader = { "<![CDATA[" };
503 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800504
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 static const int xmlHeaderLen = 2;
506 static const int commentHeaderLen = 4;
507 static const int dtdHeaderLen = 2;
508 static const int cdataHeaderLen = 9;
509 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800510
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800512#pragma warning ( push )
513#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800514#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
516 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800517#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800518#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800519#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700521 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
522 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 p += xmlHeaderLen;
524 }
525 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700526 returnNode = new (_commentPool.Alloc()) XMLComment( this );
527 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 p += commentHeaderLen;
529 }
530 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 p += cdataHeaderLen;
535 text->SetCData( true );
536 }
537 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += dtdHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_elementPool.Alloc()) XMLElement( this );
544 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += elementHeaderLen;
546 }
547 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_textPool.Alloc()) XMLText( this );
549 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p = start; // Back it up, all the text counts.
551 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800552
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 *node = returnNode;
554 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800555}
556
557
Lee Thomason751da522012-02-10 08:50:51 -0800558bool XMLDocument::Accept( XMLVisitor* visitor ) const
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 if ( visitor->VisitEnter( *this ) ) {
561 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
562 if ( !node->Accept( visitor ) ) {
563 break;
564 }
565 }
566 }
567 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800568}
Lee Thomason56bdd022012-02-09 18:16:58 -0800569
570
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571// --------- XMLNode ----------- //
572
573XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700574 _document( doc ),
575 _parent( 0 ),
576 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200577 _prev( 0 ), _next( 0 ),
578 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800580}
581
582
583XMLNode::~XMLNode()
584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700586 if ( _parent ) {
587 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700588 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800589}
590
Michael Daumling21626882013-10-22 17:03:37 +0200591const char* XMLNode::Value() const
592{
593 return _value.GetStr();
594}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800595
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800596void XMLNode::SetValue( const char* str, bool staticMem )
597{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700598 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700599 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700600 }
601 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800604}
605
606
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800607void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800608{
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 while( _firstChild ) {
610 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700612
Dmitry-Mee3225b12014-09-03 11:03:11 +0400613 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800616}
617
618
619void XMLNode::Unlink( XMLNode* child )
620{
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 if ( child == _firstChild ) {
622 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 if ( child == _lastChild ) {
625 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 }
Lee Thomasond923c672012-01-23 08:44:25 -0800627
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 if ( child->_prev ) {
629 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( child->_next ) {
632 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700634 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635}
636
637
U-Stream\Leeae25a442012-02-17 17:48:16 -0800638void XMLNode::DeleteChild( XMLNode* node )
639{
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400641 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800642}
643
644
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800645XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
646{
Michael Daumlinged523282013-10-23 07:47:29 +0200647 if (addThis->_document != _document)
648 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700649
Michael Daumlinged523282013-10-23 07:47:29 +0200650 if (addThis->_parent)
651 addThis->_parent->Unlink( addThis );
652 else
653 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700654
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( _lastChild ) {
656 TIXMLASSERT( _firstChild );
657 TIXMLASSERT( _lastChild->_next == 0 );
658 _lastChild->_next = addThis;
659 addThis->_prev = _lastChild;
660 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 }
664 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( _firstChild == 0 );
666 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_prev = 0;
669 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673}
674
675
Lee Thomason1ff38e02012-02-14 18:18:16 -0800676XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
677{
Michael Daumlinged523282013-10-23 07:47:29 +0200678 if (addThis->_document != _document)
679 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700680
Michael Daumlinged523282013-10-23 07:47:29 +0200681 if (addThis->_parent)
682 addThis->_parent->Unlink( addThis );
683 else
684 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 if ( _firstChild ) {
687 TIXMLASSERT( _lastChild );
688 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 _firstChild->_prev = addThis;
691 addThis->_next = _firstChild;
692 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
696 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 TIXMLASSERT( _lastChild == 0 );
698 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800699
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_prev = 0;
701 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200704 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705}
706
707
708XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
709{
Michael Daumlinged523282013-10-23 07:47:29 +0200710 if (addThis->_document != _document)
711 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 return 0;
717 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 // The last node or the only node.
721 return InsertEndChild( addThis );
722 }
Michael Daumlinged523282013-10-23 07:47:29 +0200723 if (addThis->_parent)
724 addThis->_parent->Unlink( addThis );
725 else
726 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_prev = afterThis;
728 addThis->_next = afterThis->_next;
729 afterThis->_next->_prev = addThis;
730 afterThis->_next = addThis;
731 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800733}
734
735
736
737
Lee Thomason56bdd022012-02-09 18:16:58 -0800738const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800739{
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 XMLElement* element = node->ToElement();
742 if ( element ) {
743 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
744 return element;
745 }
746 }
747 }
748 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800749}
750
751
Lee Thomason56bdd022012-02-09 18:16:58 -0800752const XMLElement* XMLNode::LastChildElement( const char* value ) const
753{
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 XMLElement* element = node->ToElement();
756 if ( element ) {
757 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
758 return element;
759 }
760 }
761 }
762 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800763}
764
765
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800766const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
767{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400768 for( XMLNode* node=this->_next; node; node = node->_next ) {
769 const XMLElement* element = node->ToElement();
770 if ( element
771 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
772 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 }
774 }
775 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800776}
777
778
779const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
780{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400781 for( XMLNode* node=_prev; node; node = node->_prev ) {
782 const XMLElement* element = node->ToElement();
783 if ( element
784 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
785 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 }
787 }
788 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800789}
790
791
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800792char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800793{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 // This is a recursive method, but thinking about it "at the current level"
795 // it is a pretty simple flat list:
796 // <foo/>
797 // <!-- comment -->
798 //
799 // With a special case:
800 // <foo>
801 // </foo>
802 // <!-- comment -->
803 //
804 // Where the closing element (/foo) *must* be the next thing after the opening
805 // element, and the names must match. BUT the tricky bit is that the closing
806 // element will be read by the child.
807 //
808 // 'endTag' is the end tag for this node, it is returned by a call to a child.
809 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800810
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 while( p && *p ) {
812 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 if ( p == 0 || node == 0 ) {
816 break;
817 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800818
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 StrPair endTag;
820 p = node->ParseDeep( p, &endTag );
821 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400822 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 if ( !_document->Error() ) {
825 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 }
827 break;
828 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800829
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400830 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400832 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800836 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400837 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 return p;
839 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800840
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 // Handle an end tag returned to this level.
842 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 if ( ele ) {
844 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() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 p = 0;
851 }
852 else if ( !endTag.Empty() ) {
853 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 p = 0;
856 }
857 }
858 }
859 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400860 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 node = 0;
862 }
863 if ( node ) {
864 this->InsertEndChild( node );
865 }
866 }
867 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800868}
869
Dmitry-Mee3225b12014-09-03 11:03:11 +0400870void XMLNode::DeleteNode( XMLNode* node )
871{
872 if ( node == 0 ) {
873 return;
874 }
875 MemPool* pool = node->_memPool;
876 node->~XMLNode();
877 pool->Free( node );
878}
879
Lee Thomason5492a1c2012-01-23 15:32:10 -0800880// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800881char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800882{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 const char* start = p;
884 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 return p;
890 }
891 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
893 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 flags |= StrPair::COLLAPSE_WHITESPACE;
895 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700896
Lee Thomason624d43f2012-10-12 10:58:48 -0700897 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700900 }
901 if ( p && *p ) {
902 return p-1;
903 }
904 }
905 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800906}
907
908
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
910{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700912 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 }
914 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
915 text->SetCData( this->CData() );
916 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800917}
918
919
920bool XMLText::ShallowEqual( const XMLNode* compare ) const
921{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800923}
924
925
Lee Thomason56bdd022012-02-09 18:16:58 -0800926bool XMLText::Accept( XMLVisitor* visitor ) const
927{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800929}
930
931
Lee Thomason3f57d272012-01-11 15:30:03 -0800932// --------- XMLComment ---------- //
933
Lee Thomasone4422302012-01-20 17:59:50 -0800934XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800935{
936}
937
938
Lee Thomasonce0763e2012-01-11 15:43:54 -0800939XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800940{
Lee Thomason3f57d272012-01-11 15:30:03 -0800941}
942
943
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800944char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800945{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 // Comment parses as text.
947 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700948 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700950 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 }
952 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800953}
954
955
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
957{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700959 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 }
961 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
962 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963}
964
965
966bool XMLComment::ShallowEqual( const XMLNode* compare ) const
967{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 const XMLComment* comment = compare->ToComment();
969 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800970}
971
972
Lee Thomason751da522012-02-10 08:50:51 -0800973bool XMLComment::Accept( XMLVisitor* visitor ) const
974{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800976}
Lee Thomason56bdd022012-02-09 18:16:58 -0800977
978
Lee Thomason50f97b22012-02-11 16:33:40 -0800979// --------- XMLDeclaration ---------- //
980
981XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
982{
983}
984
985
986XMLDeclaration::~XMLDeclaration()
987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800989}
990
991
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800992char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 // Declaration parses as text.
995 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700996 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001001}
1002
1003
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1005{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001007 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 }
1009 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1010 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001011}
1012
1013
1014bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1015{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001016 const XMLDeclaration* declaration = compare->ToDeclaration();
1017 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001018}
1019
1020
1021
Lee Thomason50f97b22012-02-11 16:33:40 -08001022bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001025}
1026
1027// --------- XMLUnknown ---------- //
1028
1029XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1030{
1031}
1032
1033
1034XMLUnknown::~XMLUnknown()
1035{
1036}
1037
1038
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001039char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 // Unknown parses as text.
1042 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001043
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001046 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 }
1048 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001049}
1050
1051
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001055 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 }
1057 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1058 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001059}
1060
1061
1062bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1063{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001064 const XMLUnknown* unknown = compare->ToUnknown();
1065 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001066}
1067
1068
Lee Thomason50f97b22012-02-11 16:33:40 -08001069bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001072}
1073
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001074// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001075
1076const char* XMLAttribute::Name() const
1077{
1078 return _name.GetStr();
1079}
1080
1081const char* XMLAttribute::Value() const
1082{
1083 return _value.GetStr();
1084}
1085
Lee Thomason6f381b72012-03-02 12:59:39 -08001086char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 if ( !p || !*p ) {
1091 return 0;
1092 }
Lee Thomason22aead12012-01-23 13:29:35 -08001093
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 // Skip white space before =
1095 p = XMLUtil::SkipWhiteSpace( p );
1096 if ( !p || *p != '=' ) {
1097 return 0;
1098 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001099
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 ++p; // move up to opening quote
1101 p = XMLUtil::SkipWhiteSpace( p );
1102 if ( *p != '\"' && *p != '\'' ) {
1103 return 0;
1104 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001105
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 char endTag[2] = { *p, 0 };
1107 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001108
Lee Thomason624d43f2012-10-12 10:58:48 -07001109 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001111}
1112
1113
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001114void XMLAttribute::SetName( const char* n )
1115{
Lee Thomason624d43f2012-10-12 10:58:48 -07001116 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001117}
1118
1119
Lee Thomason2fa81722012-11-09 12:37:46 -08001120XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 if ( XMLUtil::ToInt( Value(), value )) {
1123 return XML_NO_ERROR;
1124 }
1125 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126}
1127
1128
Lee Thomason2fa81722012-11-09 12:37:46 -08001129XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 if ( XMLUtil::ToUnsigned( Value(), value )) {
1132 return XML_NO_ERROR;
1133 }
1134 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135}
1136
1137
Lee Thomason2fa81722012-11-09 12:37:46 -08001138XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 if ( XMLUtil::ToBool( Value(), value )) {
1141 return XML_NO_ERROR;
1142 }
1143 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001144}
1145
1146
Lee Thomason2fa81722012-11-09 12:37:46 -08001147XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( XMLUtil::ToFloat( Value(), value )) {
1150 return XML_NO_ERROR;
1151 }
1152 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001153}
1154
1155
Lee Thomason2fa81722012-11-09 12:37:46 -08001156XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 if ( XMLUtil::ToDouble( Value(), value )) {
1159 return XML_NO_ERROR;
1160 }
1161 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162}
1163
1164
1165void XMLAttribute::SetAttribute( const char* v )
1166{
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
1169
1170
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171void XMLAttribute::SetAttribute( int v )
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 char buf[BUF_SIZE];
1174 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001177
1178
1179void XMLAttribute::SetAttribute( unsigned v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186
1187void XMLAttribute::SetAttribute( bool v )
1188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 char buf[BUF_SIZE];
1190 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001192}
1193
1194void XMLAttribute::SetAttribute( double v )
1195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 char buf[BUF_SIZE];
1197 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001198 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001199}
1200
1201void XMLAttribute::SetAttribute( float v )
1202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 char buf[BUF_SIZE];
1204 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001206}
1207
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001208
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001209// --------- XMLElement ---------- //
1210XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 _closingType( 0 ),
1212 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001213{
1214}
1215
1216
1217XMLElement::~XMLElement()
1218{
Lee Thomason624d43f2012-10-12 10:58:48 -07001219 while( _rootAttribute ) {
1220 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001221 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001224}
1225
1226
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227XMLAttribute* XMLElement::FindAttribute( const char* name )
1228{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001229 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1231 return a;
1232 }
1233 }
1234 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001235}
1236
1237
1238const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1239{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001240 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1242 return a;
1243 }
1244 }
1245 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246}
1247
1248
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001249const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 const XMLAttribute* a = FindAttribute( name );
1252 if ( !a ) {
1253 return 0;
1254 }
1255 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1256 return a->Value();
1257 }
1258 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001259}
1260
1261
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262const char* XMLElement::GetText() const
1263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 if ( FirstChild() && FirstChild()->ToText() ) {
1265 return FirstChild()->ToText()->Value();
1266 }
1267 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001268}
1269
1270
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001271void XMLElement::SetText( const char* inText )
1272{
Uli Kusterer869bb592014-01-21 01:36:16 +01001273 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001274 FirstChild()->SetValue( inText );
1275 else {
1276 XMLText* theText = GetDocument()->NewText( inText );
1277 InsertFirstChild( theText );
1278 }
1279}
1280
Lee Thomason5bb2d802014-01-24 10:42:57 -08001281
1282void XMLElement::SetText( int v )
1283{
1284 char buf[BUF_SIZE];
1285 XMLUtil::ToStr( v, buf, BUF_SIZE );
1286 SetText( buf );
1287}
1288
1289
1290void XMLElement::SetText( unsigned v )
1291{
1292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1294 SetText( buf );
1295}
1296
1297
1298void XMLElement::SetText( bool v )
1299{
1300 char buf[BUF_SIZE];
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1302 SetText( buf );
1303}
1304
1305
1306void XMLElement::SetText( float v )
1307{
1308 char buf[BUF_SIZE];
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1310 SetText( buf );
1311}
1312
1313
1314void XMLElement::SetText( double v )
1315{
1316 char buf[BUF_SIZE];
1317 XMLUtil::ToStr( v, buf, BUF_SIZE );
1318 SetText( buf );
1319}
1320
1321
MortenMacFly4ee49f12013-01-14 20:03:14 +01001322XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( FirstChild() && FirstChild()->ToText() ) {
1325 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001326 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 return XML_SUCCESS;
1328 }
1329 return XML_CAN_NOT_CONVERT_TEXT;
1330 }
1331 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001332}
1333
1334
MortenMacFly4ee49f12013-01-14 20:03:14 +01001335XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 if ( FirstChild() && FirstChild()->ToText() ) {
1338 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001339 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 return XML_SUCCESS;
1341 }
1342 return XML_CAN_NOT_CONVERT_TEXT;
1343 }
1344 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001345}
1346
1347
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( FirstChild() && FirstChild()->ToText() ) {
1351 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 return XML_SUCCESS;
1354 }
1355 return XML_CAN_NOT_CONVERT_TEXT;
1356 }
1357 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
1364 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
1377 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
1387
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001388XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 XMLAttribute* last = 0;
1391 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1396 break;
1397 }
1398 }
1399 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1401 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001403 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 }
1408 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001409 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 }
1411 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001412}
1413
1414
U-Stream\Leeae25a442012-02-17 17:48:16 -08001415void XMLElement::DeleteAttribute( const char* name )
1416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1420 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 }
1423 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001426 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 break;
1428 }
1429 prev = a;
1430 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001431}
1432
1433
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001434char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 const char* start = p;
1437 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 // Read the attributes.
1440 while( p ) {
1441 p = XMLUtil::SkipWhiteSpace( p );
1442 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 return 0;
1445 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001446
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001448 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1450 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001451 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001452
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001455 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 return 0;
1458 }
1459 // There is a minor bug here: if the attribute in the source xml
1460 // document is duplicated, it will not be detected and the
1461 // attribute will be doubly added. However, tracking the 'prevAttribute'
1462 // avoids re-scanning the attribute list. Preferring performance for
1463 // now, may reconsider in the future.
1464 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 }
1467 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 }
1470 prevAttribute = attrib;
1471 }
1472 // end of the tag
1473 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 return p+2; // done; sealed element.
1476 }
1477 // end of the tag
1478 else if ( *p == '>' ) {
1479 ++p;
1480 break;
1481 }
1482 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 return 0;
1485 }
1486 }
1487 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001488}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001489
Dmitry-Mee3225b12014-09-03 11:03:11 +04001490void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1491{
1492 if ( attribute == 0 ) {
1493 return;
1494 }
1495 MemPool* pool = attribute->_memPool;
1496 attribute->~XMLAttribute();
1497 pool->Free( attribute );
1498}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001499
Lee Thomason67d61312012-01-24 16:01:51 -08001500//
1501// <ele></ele>
1502// <ele>foo<b>bar</b></ele>
1503//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001504char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 // Read the element name.
1507 p = XMLUtil::SkipWhiteSpace( p );
1508 if ( !p ) {
1509 return 0;
1510 }
Lee Thomason67d61312012-01-24 16:01:51 -08001511
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 // The closing element is the </element> form. It is
1513 // parsed just like a regular element then deleted from
1514 // the DOM.
1515 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 ++p;
1518 }
Lee Thomason67d61312012-01-24 16:01:51 -08001519
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 p = _value.ParseName( p );
1521 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 return 0;
1523 }
Lee Thomason67d61312012-01-24 16:01:51 -08001524
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001526 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return p;
1528 }
Lee Thomason67d61312012-01-24 16:01:51 -08001529
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 p = XMLNode::ParseDeep( p, strPair );
1531 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001532}
1533
1534
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001535
1536XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 }
1541 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1542 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1543 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1544 }
1545 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001546}
1547
1548
1549bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1550{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 const XMLElement* other = compare->ToElement();
1552 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001553
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 const XMLAttribute* a=FirstAttribute();
1555 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001556
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 while ( a && b ) {
1558 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1559 return false;
1560 }
1561 a = a->Next();
1562 b = b->Next();
1563 }
1564 if ( a || b ) {
1565 // different count
1566 return false;
1567 }
1568 return true;
1569 }
1570 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571}
1572
1573
Lee Thomason751da522012-02-10 08:50:51 -08001574bool XMLElement::Accept( XMLVisitor* visitor ) const
1575{
Lee Thomason624d43f2012-10-12 10:58:48 -07001576 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1578 if ( !node->Accept( visitor ) ) {
1579 break;
1580 }
1581 }
1582 }
1583 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001584}
Lee Thomason56bdd022012-02-09 18:16:58 -08001585
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001586
Lee Thomason3f57d272012-01-11 15:30:03 -08001587// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001588XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 _writeBOM( false ),
1591 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001592 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001593 _whitespace( whitespace ),
1594 _errorStr1( 0 ),
1595 _errorStr2( 0 ),
1596 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001597{
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001599}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001600
1601
Lee Thomason3f57d272012-01-11 15:30:03 -08001602XMLDocument::~XMLDocument()
1603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001606
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001607#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001608 _textPool.Trace( "text" );
1609 _elementPool.Trace( "element" );
1610 _commentPool.Trace( "comment" );
1611 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001612#endif
1613
Lee Thomason5b0a6772012-11-19 13:54:42 -08001614#ifdef DEBUG
1615 if ( Error() == false ) {
1616 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1617 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1618 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1619 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1620 }
1621#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001622}
1623
1624
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001625void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001626{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001627 DeleteChildren();
1628
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 _errorID = XML_NO_ERROR;
1630 _errorStr1 = 0;
1631 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001632
Lee Thomason624d43f2012-10-12 10:58:48 -07001633 delete [] _charBuffer;
1634 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001635}
1636
Lee Thomason3f57d272012-01-11 15:30:03 -08001637
Lee Thomason2c85a712012-01-31 08:24:24 -08001638XMLElement* XMLDocument::NewElement( const char* name )
1639{
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1641 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 ele->SetName( name );
1643 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001644}
1645
1646
Lee Thomason1ff38e02012-02-14 18:18:16 -08001647XMLComment* XMLDocument::NewComment( const char* str )
1648{
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1650 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 comment->SetValue( str );
1652 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001653}
1654
1655
1656XMLText* XMLDocument::NewText( const char* str )
1657{
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1659 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 text->SetValue( str );
1661 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001662}
1663
1664
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001665XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1666{
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1668 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1670 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001671}
1672
1673
1674XMLUnknown* XMLDocument::NewUnknown( const char* str )
1675{
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1677 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 unk->SetValue( str );
1679 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001680}
1681
Dmitry-Me01578db2014-08-19 10:18:48 +04001682static FILE* callfopen( const char* filepath, const char* mode )
1683{
1684#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1685 FILE* fp = 0;
1686 errno_t err = fopen_s( &fp, filepath, mode );
1687 if ( err ) {
1688 return 0;
1689 }
1690#else
1691 FILE* fp = fopen( filepath, mode );
1692#endif
1693 return fp;
1694}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001695
Lee Thomason2fa81722012-11-09 12:37:46 -08001696XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001697{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001698 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001699 FILE* fp = callfopen( filename, "rb" );
1700 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001702 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 }
1704 LoadFile( fp );
1705 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001707}
1708
1709
Lee Thomason2fa81722012-11-09 12:37:46 -08001710XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001711{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001712 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001713
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001714 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001715 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001716 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1717 return _errorID;
1718 }
1719
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001721 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001723 if ( filelength == -1L ) {
1724 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1725 return _errorID;
1726 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001728 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001730 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001733
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 _charBuffer = new char[size+1];
1735 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 if ( read != size ) {
1737 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001740
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001742
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 if ( !p || !*p ) {
1747 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001750
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1752 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001753}
1754
1755
Lee Thomason2fa81722012-11-09 12:37:46 -08001756XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001757{
Dmitry-Me01578db2014-08-19 10:18:48 +04001758 FILE* fp = callfopen( filename, "w" );
1759 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 }
1763 SaveFile(fp, compact);
1764 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001766}
1767
1768
Lee Thomason2fa81722012-11-09 12:37:46 -08001769XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001770{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 XMLPrinter stream( fp, compact );
1772 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001774}
1775
Lee Thomason1ff38e02012-02-14 18:18:16 -08001776
Lee Thomason2fa81722012-11-09 12:37:46 -08001777XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001778{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001779 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001780 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001781
Lee Thomason82d32002014-02-21 22:47:18 -08001782 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
1786 if ( len == (size_t)(-1) ) {
1787 len = strlen( p );
1788 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 _charBuffer = new char[ len+1 ];
1790 memcpy( _charBuffer, p, len );
1791 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001792
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 if ( !p || !*p ) {
1796 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001799
Thomas Roß1470edc2013-05-10 15:44:12 +02001800 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001801 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001803}
1804
1805
PKEuS1c5f99e2013-07-06 11:28:39 +02001806void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001807{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 XMLPrinter stdStreamer( stdout );
1809 if ( !streamer ) {
1810 streamer = &stdStreamer;
1811 }
1812 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001813}
1814
1815
Lee Thomason2fa81722012-11-09 12:37:46 -08001816void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001817{
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 _errorID = error;
1819 _errorStr1 = str1;
1820 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001821}
1822
Lee Thomason5cae8972012-01-24 18:03:07 -08001823
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001824void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825{
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 static const int LEN = 20;
1828 char buf1[LEN] = { 0 };
1829 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001830
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 if ( _errorStr1 ) {
1832 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 if ( _errorStr2 ) {
1835 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001841}
1842
1843
PKEuS1bfb9542013-08-04 13:51:17 +02001844XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _elementJustOpened( false ),
1846 _firstElement( true ),
1847 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001848 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _textDepth( -1 ),
1850 _processEntities( true ),
1851 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001852{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _entityFlag[i] = false;
1855 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
1857 for( int i=0; i<NUM_ENTITIES; ++i ) {
1858 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1859 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 }
1862 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 _restrictedEntityFlag[(int)'&'] = true;
1864 _restrictedEntityFlag[(int)'<'] = true;
1865 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1866 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001867}
1868
1869
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001870void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001871{
1872 va_list va;
1873 va_start( va, format );
1874
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 if ( _fp ) {
1876 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 }
1878 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001879#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001880 #if defined(WINCE)
1881 int len = 512;
1882 do {
1883 len = len*2;
1884 char* str = new char[len]();
1885 len = _vsnprintf(str, len, format, va);
1886 delete[] str;
1887 }while (len < 0);
1888 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001889 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001890 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891#else
1892 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001893#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 // Close out and re-start the va-args
1895 va_end( va );
1896 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001897 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1898#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001899 #if defined(WINCE)
1900 _vsnprintf( p, len+1, format, va );
1901 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001902 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001903 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001904#else
1905 vsnprintf( p, len+1, format, va );
1906#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001908 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001909}
1910
1911
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001912void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 for( int i=0; i<depth; ++i ) {
1915 Print( " " );
1916 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001917}
1918
1919
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001920void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001921{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 // Look for runs of bytes between entities to print.
1923 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001925
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 while ( *q ) {
1928 // Remember, char is sometimes signed. (How many times has that bitten me?)
1929 if ( *q > 0 && *q < ENTITY_RANGE ) {
1930 // Check for entities. If one is found, flush
1931 // the stream up until the entity, write the
1932 // entity, and keep looking.
1933 if ( flag[(unsigned)(*q)] ) {
1934 while ( p < q ) {
1935 Print( "%c", *p );
1936 ++p;
1937 }
1938 for( int i=0; i<NUM_ENTITIES; ++i ) {
1939 if ( entities[i].value == *q ) {
1940 Print( "&%s;", entities[i].pattern );
1941 break;
1942 }
1943 }
1944 ++p;
1945 }
1946 }
1947 ++q;
1948 }
1949 }
1950 // Flush the remaining string. This will be the entire
1951 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 Print( "%s", p );
1954 }
Lee Thomason857b8682012-01-25 17:50:25 -08001955}
1956
U-Stream\Leeae25a442012-02-17 17:48:16 -08001957
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001958void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001961 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 -07001962 Print( "%s", bom );
1963 }
1964 if ( writeDec ) {
1965 PushDeclaration( "xml version=\"1.0\"" );
1966 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001967}
1968
1969
Uli Kusterer593a33d2014-02-01 12:48:51 +01001970void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001971{
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 SealElement();
1974 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001976
Uli Kusterer593a33d2014-02-01 12:48:51 +01001977 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001979 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001980 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001982 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001983
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001984 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 _elementJustOpened = true;
1986 _firstElement = false;
1987 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001988}
1989
1990
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001991void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001992{
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 Print( " %s=\"", name );
1995 PrintString( value, false );
1996 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001997}
1998
1999
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002000void XMLPrinter::PushAttribute( const char* name, int v )
2001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 char buf[BUF_SIZE];
2003 XMLUtil::ToStr( v, buf, BUF_SIZE );
2004 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002005}
2006
2007
2008void XMLPrinter::PushAttribute( const char* name, unsigned v )
2009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 char buf[BUF_SIZE];
2011 XMLUtil::ToStr( v, buf, BUF_SIZE );
2012 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002013}
2014
2015
2016void XMLPrinter::PushAttribute( const char* name, bool v )
2017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 char buf[BUF_SIZE];
2019 XMLUtil::ToStr( v, buf, BUF_SIZE );
2020 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002021}
2022
2023
2024void XMLPrinter::PushAttribute( const char* name, double v )
2025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 char buf[BUF_SIZE];
2027 XMLUtil::ToStr( v, buf, BUF_SIZE );
2028 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002029}
2030
2031
Uli Kustererca412e82014-02-01 13:35:05 +01002032void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002033{
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 --_depth;
2035 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002036
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 Print( "/>" );
2039 }
2040 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002041 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002043 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 }
2045 Print( "</%s>", name );
2046 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002047
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _textDepth == _depth ) {
2049 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 }
Uli Kustererca412e82014-02-01 13:35:05 +01002051 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( "\n" );
2053 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002055}
2056
2057
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002058void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002059{
Lee Thomason624d43f2012-10-12 10:58:48 -07002060 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002062}
2063
2064
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002065void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002066{
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002068
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 SealElement();
2071 }
2072 if ( cdata ) {
2073 Print( "<![CDATA[" );
2074 Print( "%s", text );
2075 Print( "]]>" );
2076 }
2077 else {
2078 PrintString( text, true );
2079 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002082void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 char buf[BUF_SIZE];
2085 XMLUtil::ToStr( value, buf, BUF_SIZE );
2086 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002087}
2088
2089
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002090void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 char buf[BUF_SIZE];
2093 XMLUtil::ToStr( value, buf, BUF_SIZE );
2094 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002095}
2096
2097
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002098void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( value, buf, BUF_SIZE );
2102 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002103}
2104
2105
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002106void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 char buf[BUF_SIZE];
2109 XMLUtil::ToStr( value, buf, BUF_SIZE );
2110 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002111}
2112
2113
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002114void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 char buf[BUF_SIZE];
2117 XMLUtil::ToStr( value, buf, BUF_SIZE );
2118 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002119}
2120
Lee Thomason5cae8972012-01-24 18:03:07 -08002121
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002122void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002123{
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 SealElement();
2126 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002133}
Lee Thomason751da522012-02-10 08:50:51 -08002134
2135
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002136void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002137{
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 SealElement();
2140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147}
2148
2149
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002150void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002151{
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 SealElement();
2154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002161}
2162
2163
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002164bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002165{
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 if ( doc.HasBOM() ) {
2168 PushHeader( true, false );
2169 }
2170 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002171}
2172
2173
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002174bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002175{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002176 const XMLElement* parentElem = element.Parent()->ToElement();
2177 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2178 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 while ( attribute ) {
2180 PushAttribute( attribute->Name(), attribute->Value() );
2181 attribute = attribute->Next();
2182 }
2183 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002184}
2185
2186
Uli Kustererca412e82014-02-01 13:35:05 +01002187bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002188{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002189 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002191}
2192
2193
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002194bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 PushText( text.Value(), text.CData() );
2197 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002198}
2199
2200
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002201bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 PushComment( comment.Value() );
2204 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002205}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002206
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002207bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 PushDeclaration( declaration.Value() );
2210 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002211}
2212
2213
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002214bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002215{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 PushUnknown( unknown.Value() );
2217 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002218}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002219
Lee Thomason685b8952012-11-12 13:00:06 -08002220} // namespace tinyxml2
2221