blob: 53d78bd2f87595983f4903d255f98523da7779fb [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
479
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700480char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 XMLNode* returnNode = 0;
483 char* start = p;
484 p = XMLUtil::SkipWhiteSpace( p );
485 if( !p || !*p ) {
486 return p;
487 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800488
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800490 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 static const char* xmlHeader = { "<?" };
492 static const char* commentHeader = { "<!--" };
493 static const char* dtdHeader = { "<!" };
494 static const char* cdataHeader = { "<![CDATA[" };
495 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 static const int xmlHeaderLen = 2;
498 static const int commentHeaderLen = 4;
499 static const int dtdHeaderLen = 2;
500 static const int cdataHeaderLen = 9;
501 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800503#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800504#pragma warning ( push )
505#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800506#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
508 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800509#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800510#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700513 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
514 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 p += xmlHeaderLen;
516 }
517 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700518 returnNode = new (_commentPool.Alloc()) XMLComment( this );
519 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 p += commentHeaderLen;
521 }
522 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700523 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700525 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 p += cdataHeaderLen;
527 text->SetCData( true );
528 }
529 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700530 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
531 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p += dtdHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700535 returnNode = new (_elementPool.Alloc()) XMLElement( this );
536 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 p += elementHeaderLen;
538 }
539 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_textPool.Alloc()) XMLText( this );
541 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = start; // Back it up, all the text counts.
543 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 *node = returnNode;
546 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800547}
548
549
Lee Thomason751da522012-02-10 08:50:51 -0800550bool XMLDocument::Accept( XMLVisitor* visitor ) const
551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 if ( visitor->VisitEnter( *this ) ) {
553 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
554 if ( !node->Accept( visitor ) ) {
555 break;
556 }
557 }
558 }
559 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800560}
Lee Thomason56bdd022012-02-09 18:16:58 -0800561
562
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563// --------- XMLNode ----------- //
564
565XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 _document( doc ),
567 _parent( 0 ),
568 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200569 _prev( 0 ), _next( 0 ),
570 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800572}
573
574
575XMLNode::~XMLNode()
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700578 if ( _parent ) {
579 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800581}
582
Michael Daumling21626882013-10-22 17:03:37 +0200583const char* XMLNode::Value() const
584{
585 return _value.GetStr();
586}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800587
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800588void XMLNode::SetValue( const char* str, bool staticMem )
589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700591 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 }
593 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800596}
597
598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800599void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600{
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 while( _firstChild ) {
602 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700604
Dmitry-Mee3225b12014-09-03 11:03:11 +0400605 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800608}
609
610
611void XMLNode::Unlink( XMLNode* child )
612{
Lee Thomason624d43f2012-10-12 10:58:48 -0700613 if ( child == _firstChild ) {
614 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 if ( child == _lastChild ) {
617 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
Lee Thomasond923c672012-01-23 08:44:25 -0800619
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( child->_prev ) {
621 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 if ( child->_next ) {
624 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700626 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627}
628
629
U-Stream\Leeae25a442012-02-17 17:48:16 -0800630void XMLNode::DeleteChild( XMLNode* node )
631{
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400633 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800634}
635
636
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800637XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
638{
Michael Daumlinged523282013-10-23 07:47:29 +0200639 if (addThis->_document != _document)
640 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641
Michael Daumlinged523282013-10-23 07:47:29 +0200642 if (addThis->_parent)
643 addThis->_parent->Unlink( addThis );
644 else
645 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( _lastChild ) {
648 TIXMLASSERT( _firstChild );
649 TIXMLASSERT( _lastChild->_next == 0 );
650 _lastChild->_next = addThis;
651 addThis->_prev = _lastChild;
652 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 TIXMLASSERT( _firstChild == 0 );
658 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_prev = 0;
661 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665}
666
667
Lee Thomason1ff38e02012-02-14 18:18:16 -0800668XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
669{
Michael Daumlinged523282013-10-23 07:47:29 +0200670 if (addThis->_document != _document)
671 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700672
Michael Daumlinged523282013-10-23 07:47:29 +0200673 if (addThis->_parent)
674 addThis->_parent->Unlink( addThis );
675 else
676 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( _firstChild ) {
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 _firstChild->_prev = addThis;
683 addThis->_next = _firstChild;
684 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
688 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_prev = 0;
693 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Michael Daumlinged523282013-10-23 07:47:29 +0200702 if (addThis->_document != _document)
703 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 return 0;
709 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 // The last node or the only node.
713 return InsertEndChild( addThis );
714 }
Michael Daumlinged523282013-10-23 07:47:29 +0200715 if (addThis->_parent)
716 addThis->_parent->Unlink( addThis );
717 else
718 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = afterThis;
720 addThis->_next = afterThis->_next;
721 afterThis->_next->_prev = addThis;
722 afterThis->_next = addThis;
723 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725}
726
727
728
729
Lee Thomason56bdd022012-02-09 18:16:58 -0800730const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800731{
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 XMLElement* element = node->ToElement();
734 if ( element ) {
735 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
736 return element;
737 }
738 }
739 }
740 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800741}
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::LastChildElement( const char* value ) const
745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800755}
756
757
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800758const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
759{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400760 for( XMLNode* node=this->_next; node; node = node->_next ) {
761 const XMLElement* element = node->ToElement();
762 if ( element
763 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
764 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
771const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
772{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400773 for( XMLNode* node=_prev; node; node = node->_prev ) {
774 const XMLElement* element = node->ToElement();
775 if ( element
776 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
777 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // This is a recursive method, but thinking about it "at the current level"
787 // it is a pretty simple flat list:
788 // <foo/>
789 // <!-- comment -->
790 //
791 // With a special case:
792 // <foo>
793 // </foo>
794 // <!-- comment -->
795 //
796 // Where the closing element (/foo) *must* be the next thing after the opening
797 // element, and the names must match. BUT the tricky bit is that the closing
798 // element will be read by the child.
799 //
800 // 'endTag' is the end tag for this node, it is returned by a call to a child.
801 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800802
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 while( p && *p ) {
804 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 if ( p == 0 || node == 0 ) {
808 break;
809 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800810
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 StrPair endTag;
812 p = node->ParseDeep( p, &endTag );
813 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( !_document->Error() ) {
817 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 break;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400822 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400824 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800828 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400829 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 return p;
831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // Handle an end tag returned to this level.
834 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 if ( ele ) {
836 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 p = 0;
839 }
840 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 p = 0;
843 }
844 else if ( !endTag.Empty() ) {
845 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 p = 0;
848 }
849 }
850 }
851 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400852 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 node = 0;
854 }
855 if ( node ) {
856 this->InsertEndChild( node );
857 }
858 }
859 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800860}
861
Dmitry-Mee3225b12014-09-03 11:03:11 +0400862void XMLNode::DeleteNode( XMLNode* node )
863{
864 if ( node == 0 ) {
865 return;
866 }
867 MemPool* pool = node->_memPool;
868 node->~XMLNode();
869 pool->Free( node );
870}
871
Lee Thomason5492a1c2012-01-23 15:32:10 -0800872// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800873char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 const char* start = p;
876 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 return p;
882 }
883 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
885 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 flags |= StrPair::COLLAPSE_WHITESPACE;
887 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 }
893 if ( p && *p ) {
894 return p-1;
895 }
896 }
897 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800898}
899
900
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800901XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
902{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 }
906 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
907 text->SetCData( this->CData() );
908 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909}
910
911
912bool XMLText::ShallowEqual( const XMLNode* compare ) const
913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800915}
916
917
Lee Thomason56bdd022012-02-09 18:16:58 -0800918bool XMLText::Accept( XMLVisitor* visitor ) const
919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800921}
922
923
Lee Thomason3f57d272012-01-11 15:30:03 -0800924// --------- XMLComment ---------- //
925
Lee Thomasone4422302012-01-20 17:59:50 -0800926XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800927{
928}
929
930
Lee Thomasonce0763e2012-01-11 15:43:54 -0800931XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800932{
Lee Thomason3f57d272012-01-11 15:30:03 -0800933}
934
935
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800936char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 // Comment parses as text.
939 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800945}
946
947
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
954 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
958bool XMLComment::ShallowEqual( const XMLNode* compare ) const
959{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400960 const XMLComment* comment = compare->ToComment();
961 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800962}
963
964
Lee Thomason751da522012-02-10 08:50:51 -0800965bool XMLComment::Accept( XMLVisitor* visitor ) const
966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800968}
Lee Thomason56bdd022012-02-09 18:16:58 -0800969
970
Lee Thomason50f97b22012-02-11 16:33:40 -0800971// --------- XMLDeclaration ---------- //
972
973XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
974{
975}
976
977
978XMLDeclaration::~XMLDeclaration()
979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800981}
982
983
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800984char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 // Declaration parses as text.
987 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800993}
994
995
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1002 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001003}
1004
1005
1006bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1007{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLDeclaration* declaration = compare->ToDeclaration();
1009 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019// --------- XMLUnknown ---------- //
1020
1021XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLUnknown::~XMLUnknown()
1027{
1028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Unknown parses as text.
1034 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1050 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1055{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001056 const XMLUnknown* unknown = compare->ToUnknown();
1057 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001067
1068const char* XMLAttribute::Name() const
1069{
1070 return _name.GetStr();
1071}
1072
1073const char* XMLAttribute::Value() const
1074{
1075 return _value.GetStr();
1076}
1077
Lee Thomason6f381b72012-03-02 12:59:39 -08001078char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p || !*p ) {
1083 return 0;
1084 }
Lee Thomason22aead12012-01-23 13:29:35 -08001085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Skip white space before =
1087 p = XMLUtil::SkipWhiteSpace( p );
1088 if ( !p || *p != '=' ) {
1089 return 0;
1090 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 ++p; // move up to opening quote
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( *p != '\"' && *p != '\'' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 char endTag[2] = { *p, 0 };
1099 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106void XMLAttribute::SetName( const char* n )
1107{
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToInt( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
Lee Thomason2fa81722012-11-09 12:37:46 -08001121XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( XMLUtil::ToUnsigned( Value(), value )) {
1124 return XML_NO_ERROR;
1125 }
1126 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason2fa81722012-11-09 12:37:46 -08001130XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( XMLUtil::ToBool( Value(), value )) {
1133 return XML_NO_ERROR;
1134 }
1135 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToFloat( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToDouble( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
1157void XMLAttribute::SetAttribute( const char* v )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163void XMLAttribute::SetAttribute( int v )
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 char buf[BUF_SIZE];
1166 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169
1170
1171void XMLAttribute::SetAttribute( unsigned 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 Thomason1a1d4a72012-02-15 09:09:25 -08001176}
1177
1178
1179void XMLAttribute::SetAttribute( bool 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
1186void XMLAttribute::SetAttribute( double v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193void XMLAttribute::SetAttribute( float v )
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char buf[BUF_SIZE];
1196 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001198}
1199
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001200
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001201// --------- XMLElement ---------- //
1202XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _closingType( 0 ),
1204 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205{
1206}
1207
1208
1209XMLElement::~XMLElement()
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 while( _rootAttribute ) {
1212 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001213 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001216}
1217
1218
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219XMLAttribute* XMLElement::FindAttribute( const char* name )
1220{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001221 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1223 return a;
1224 }
1225 }
1226 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227}
1228
1229
1230const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1231{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001232 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1234 return a;
1235 }
1236 }
1237 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001241const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 const XMLAttribute* a = FindAttribute( name );
1244 if ( !a ) {
1245 return 0;
1246 }
1247 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1248 return a->Value();
1249 }
1250 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001251}
1252
1253
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001254const char* XMLElement::GetText() const
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 return FirstChild()->ToText()->Value();
1258 }
1259 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001260}
1261
1262
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001263void XMLElement::SetText( const char* inText )
1264{
Uli Kusterer869bb592014-01-21 01:36:16 +01001265 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001266 FirstChild()->SetValue( inText );
1267 else {
1268 XMLText* theText = GetDocument()->NewText( inText );
1269 InsertFirstChild( theText );
1270 }
1271}
1272
Lee Thomason5bb2d802014-01-24 10:42:57 -08001273
1274void XMLElement::SetText( int v )
1275{
1276 char buf[BUF_SIZE];
1277 XMLUtil::ToStr( v, buf, BUF_SIZE );
1278 SetText( buf );
1279}
1280
1281
1282void XMLElement::SetText( unsigned v )
1283{
1284 char buf[BUF_SIZE];
1285 XMLUtil::ToStr( v, buf, BUF_SIZE );
1286 SetText( buf );
1287}
1288
1289
1290void XMLElement::SetText( bool v )
1291{
1292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1294 SetText( buf );
1295}
1296
1297
1298void XMLElement::SetText( float v )
1299{
1300 char buf[BUF_SIZE];
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1302 SetText( buf );
1303}
1304
1305
1306void XMLElement::SetText( double v )
1307{
1308 char buf[BUF_SIZE];
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1310 SetText( buf );
1311}
1312
1313
MortenMacFly4ee49f12013-01-14 20:03:14 +01001314XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( FirstChild() && FirstChild()->ToText() ) {
1317 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001318 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return XML_SUCCESS;
1320 }
1321 return XML_CAN_NOT_CONVERT_TEXT;
1322 }
1323 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001324}
1325
1326
MortenMacFly4ee49f12013-01-14 20:03:14 +01001327XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( FirstChild() && FirstChild()->ToText() ) {
1330 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001331 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 return XML_SUCCESS;
1333 }
1334 return XML_CAN_NOT_CONVERT_TEXT;
1335 }
1336 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001337}
1338
1339
MortenMacFly4ee49f12013-01-14 20:03:14 +01001340XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( FirstChild() && FirstChild()->ToText() ) {
1343 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001344 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 return XML_SUCCESS;
1346 }
1347 return XML_CAN_NOT_CONVERT_TEXT;
1348 }
1349 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001350}
1351
1352
MortenMacFly4ee49f12013-01-14 20:03:14 +01001353XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( FirstChild() && FirstChild()->ToText() ) {
1356 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return XML_SUCCESS;
1359 }
1360 return XML_CAN_NOT_CONVERT_TEXT;
1361 }
1362 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001363}
1364
1365
MortenMacFly4ee49f12013-01-14 20:03:14 +01001366XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 if ( FirstChild() && FirstChild()->ToText() ) {
1369 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 return XML_SUCCESS;
1372 }
1373 return XML_CAN_NOT_CONVERT_TEXT;
1374 }
1375 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001376}
1377
1378
1379
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001380XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 XMLAttribute* last = 0;
1383 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001384 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1388 break;
1389 }
1390 }
1391 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1393 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 }
1397 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001401 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001404}
1405
1406
U-Stream\Leeae25a442012-02-17 17:48:16 -08001407void XMLElement::DeleteAttribute( const char* name )
1408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1412 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 }
1415 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001418 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 break;
1420 }
1421 prev = a;
1422 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001423}
1424
1425
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001426char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 const char* start = p;
1429 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001430
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 // Read the attributes.
1432 while( p ) {
1433 p = XMLUtil::SkipWhiteSpace( p );
1434 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 return 0;
1437 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001440 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001441 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1442 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001443 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001444
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001447 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 return 0;
1450 }
1451 // There is a minor bug here: if the attribute in the source xml
1452 // document is duplicated, it will not be detected and the
1453 // attribute will be doubly added. However, tracking the 'prevAttribute'
1454 // avoids re-scanning the attribute list. Preferring performance for
1455 // now, may reconsider in the future.
1456 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 prevAttribute = attrib;
1463 }
1464 // end of the tag
1465 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 return p+2; // done; sealed element.
1468 }
1469 // end of the tag
1470 else if ( *p == '>' ) {
1471 ++p;
1472 break;
1473 }
1474 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 return 0;
1477 }
1478 }
1479 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001480}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481
Dmitry-Mee3225b12014-09-03 11:03:11 +04001482void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1483{
1484 if ( attribute == 0 ) {
1485 return;
1486 }
1487 MemPool* pool = attribute->_memPool;
1488 attribute->~XMLAttribute();
1489 pool->Free( attribute );
1490}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491
Lee Thomason67d61312012-01-24 16:01:51 -08001492//
1493// <ele></ele>
1494// <ele>foo<b>bar</b></ele>
1495//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001496char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 // Read the element name.
1499 p = XMLUtil::SkipWhiteSpace( p );
1500 if ( !p ) {
1501 return 0;
1502 }
Lee Thomason67d61312012-01-24 16:01:51 -08001503
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 // The closing element is the </element> form. It is
1505 // parsed just like a regular element then deleted from
1506 // the DOM.
1507 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 ++p;
1510 }
Lee Thomason67d61312012-01-24 16:01:51 -08001511
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 p = _value.ParseName( p );
1513 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
Lee Thomason67d61312012-01-24 16:01:51 -08001516
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 return p;
1520 }
Lee Thomason67d61312012-01-24 16:01:51 -08001521
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 p = XMLNode::ParseDeep( p, strPair );
1523 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001524}
1525
1526
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001527
1528XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 }
1533 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1534 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1535 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1536 }
1537 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001538}
1539
1540
1541bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 const XMLElement* other = compare->ToElement();
1544 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001545
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 const XMLAttribute* a=FirstAttribute();
1547 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 while ( a && b ) {
1550 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1551 return false;
1552 }
1553 a = a->Next();
1554 b = b->Next();
1555 }
1556 if ( a || b ) {
1557 // different count
1558 return false;
1559 }
1560 return true;
1561 }
1562 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563}
1564
1565
Lee Thomason751da522012-02-10 08:50:51 -08001566bool XMLElement::Accept( XMLVisitor* visitor ) const
1567{
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1570 if ( !node->Accept( visitor ) ) {
1571 break;
1572 }
1573 }
1574 }
1575 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001576}
Lee Thomason56bdd022012-02-09 18:16:58 -08001577
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578
Lee Thomason3f57d272012-01-11 15:30:03 -08001579// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001580
1581// Warning: List must match 'enum XMLError'
1582const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1583 "XML_SUCCESS",
1584 "XML_NO_ATTRIBUTE",
1585 "XML_WRONG_ATTRIBUTE_TYPE",
1586 "XML_ERROR_FILE_NOT_FOUND",
1587 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1588 "XML_ERROR_FILE_READ_ERROR",
1589 "XML_ERROR_ELEMENT_MISMATCH",
1590 "XML_ERROR_PARSING_ELEMENT",
1591 "XML_ERROR_PARSING_ATTRIBUTE",
1592 "XML_ERROR_IDENTIFYING_TAG",
1593 "XML_ERROR_PARSING_TEXT",
1594 "XML_ERROR_PARSING_CDATA",
1595 "XML_ERROR_PARSING_COMMENT",
1596 "XML_ERROR_PARSING_DECLARATION",
1597 "XML_ERROR_PARSING_UNKNOWN",
1598 "XML_ERROR_EMPTY_DOCUMENT",
1599 "XML_ERROR_MISMATCHED_ELEMENT",
1600 "XML_ERROR_PARSING",
1601 "XML_CAN_NOT_CONVERT_TEXT",
1602 "XML_NO_TEXT_NODE"
1603};
1604
1605
Lee Thomason624d43f2012-10-12 10:58:48 -07001606XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 _writeBOM( false ),
1609 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001610 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 _whitespace( whitespace ),
1612 _errorStr1( 0 ),
1613 _errorStr2( 0 ),
1614 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001615{
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001617}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001618
1619
Lee Thomason3f57d272012-01-11 15:30:03 -08001620XMLDocument::~XMLDocument()
1621{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001624
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001625#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001626 _textPool.Trace( "text" );
1627 _elementPool.Trace( "element" );
1628 _commentPool.Trace( "comment" );
1629 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001630#endif
1631
Lee Thomason5b0a6772012-11-19 13:54:42 -08001632#ifdef DEBUG
1633 if ( Error() == false ) {
1634 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1635 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1636 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1637 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1638 }
1639#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001640}
1641
1642
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001643void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001644{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001645 DeleteChildren();
1646
Lee Thomason624d43f2012-10-12 10:58:48 -07001647 _errorID = XML_NO_ERROR;
1648 _errorStr1 = 0;
1649 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001650
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 delete [] _charBuffer;
1652 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001653}
1654
Lee Thomason3f57d272012-01-11 15:30:03 -08001655
Lee Thomason2c85a712012-01-31 08:24:24 -08001656XMLElement* XMLDocument::NewElement( const char* name )
1657{
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1659 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 ele->SetName( name );
1661 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001662}
1663
1664
Lee Thomason1ff38e02012-02-14 18:18:16 -08001665XMLComment* XMLDocument::NewComment( const char* str )
1666{
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1668 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 comment->SetValue( str );
1670 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001671}
1672
1673
1674XMLText* XMLDocument::NewText( const char* str )
1675{
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1677 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 text->SetValue( str );
1679 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001680}
1681
1682
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001683XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1684{
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1686 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1688 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001689}
1690
1691
1692XMLUnknown* XMLDocument::NewUnknown( const char* str )
1693{
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1695 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 unk->SetValue( str );
1697 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001698}
1699
Dmitry-Me01578db2014-08-19 10:18:48 +04001700static FILE* callfopen( const char* filepath, const char* mode )
1701{
1702#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1703 FILE* fp = 0;
1704 errno_t err = fopen_s( &fp, filepath, mode );
1705 if ( err ) {
1706 return 0;
1707 }
1708#else
1709 FILE* fp = fopen( filepath, mode );
1710#endif
1711 return fp;
1712}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001713
Lee Thomason2fa81722012-11-09 12:37:46 -08001714XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001715{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001716 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001717 FILE* fp = callfopen( filename, "rb" );
1718 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001719 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 }
1722 LoadFile( fp );
1723 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001725}
1726
1727
Lee Thomason2fa81722012-11-09 12:37:46 -08001728XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001729{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001730 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001732 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001733 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001734 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1735 return _errorID;
1736 }
1737
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001739 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001741 if ( filelength == -1L ) {
1742 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1743 return _errorID;
1744 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001745
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001746 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001748 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001751
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 _charBuffer = new char[size+1];
1753 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 if ( read != size ) {
1755 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001758
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001760
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 if ( !p || !*p ) {
1765 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001768
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1770 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001771}
1772
1773
Lee Thomason2fa81722012-11-09 12:37:46 -08001774XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001775{
Dmitry-Me01578db2014-08-19 10:18:48 +04001776 FILE* fp = callfopen( filename, "w" );
1777 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 }
1781 SaveFile(fp, compact);
1782 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001784}
1785
1786
Lee Thomason2fa81722012-11-09 12:37:46 -08001787XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001788{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 XMLPrinter stream( fp, compact );
1790 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001792}
1793
Lee Thomason1ff38e02012-02-14 18:18:16 -08001794
Lee Thomason2fa81722012-11-09 12:37:46 -08001795XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001796{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001797 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001798 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001799
Lee Thomason82d32002014-02-21 22:47:18 -08001800 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 }
1804 if ( len == (size_t)(-1) ) {
1805 len = strlen( p );
1806 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001807 _charBuffer = new char[ len+1 ];
1808 memcpy( _charBuffer, p, len );
1809 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001810
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 if ( !p || !*p ) {
1814 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001817
Thomas Roß1470edc2013-05-10 15:44:12 +02001818 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001819 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001821}
1822
1823
PKEuS1c5f99e2013-07-06 11:28:39 +02001824void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001825{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 XMLPrinter stdStreamer( stdout );
1827 if ( !streamer ) {
1828 streamer = &stdStreamer;
1829 }
1830 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001831}
1832
1833
Lee Thomason2fa81722012-11-09 12:37:46 -08001834void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001835{
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 _errorID = error;
1837 _errorStr1 = str1;
1838 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001839}
1840
Lee Thomason331596e2014-09-11 14:56:43 -07001841const char* XMLDocument::ErrorName() const
1842{
1843 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1844 return _errorNames[_errorID];
1845}
Lee Thomason5cae8972012-01-24 18:03:07 -08001846
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001847void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848{
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 static const int LEN = 20;
1851 char buf1[LEN] = { 0 };
1852 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001853
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 if ( _errorStr1 ) {
1855 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 if ( _errorStr2 ) {
1858 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001860
Lee Thomason331596e2014-09-11 14:56:43 -07001861 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1862 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001864}
1865
1866
PKEuS1bfb9542013-08-04 13:51:17 +02001867XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 _elementJustOpened( false ),
1869 _firstElement( true ),
1870 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001871 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _textDepth( -1 ),
1873 _processEntities( true ),
1874 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001875{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001877 _entityFlag[i] = false;
1878 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 }
1880 for( int i=0; i<NUM_ENTITIES; ++i ) {
1881 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1882 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 }
1885 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 _restrictedEntityFlag[(int)'&'] = true;
1887 _restrictedEntityFlag[(int)'<'] = true;
1888 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1889 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001890}
1891
1892
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001893void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001894{
1895 va_list va;
1896 va_start( va, format );
1897
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 if ( _fp ) {
1899 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 }
1901 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001902#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001903 #if defined(WINCE)
1904 int len = 512;
1905 do {
1906 len = len*2;
1907 char* str = new char[len]();
1908 len = _vsnprintf(str, len, format, va);
1909 delete[] str;
1910 }while (len < 0);
1911 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001912 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001913 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914#else
1915 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001916#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 // Close out and re-start the va-args
1918 va_end( va );
1919 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001920 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1921#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001922 #if defined(WINCE)
1923 _vsnprintf( p, len+1, format, va );
1924 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001925 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001926 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001927#else
1928 vsnprintf( p, len+1, format, va );
1929#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001931 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001932}
1933
1934
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001935void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001936{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 for( int i=0; i<depth; ++i ) {
1938 Print( " " );
1939 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001940}
1941
1942
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001943void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001944{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 // Look for runs of bytes between entities to print.
1946 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001948
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 while ( *q ) {
1951 // Remember, char is sometimes signed. (How many times has that bitten me?)
1952 if ( *q > 0 && *q < ENTITY_RANGE ) {
1953 // Check for entities. If one is found, flush
1954 // the stream up until the entity, write the
1955 // entity, and keep looking.
1956 if ( flag[(unsigned)(*q)] ) {
1957 while ( p < q ) {
1958 Print( "%c", *p );
1959 ++p;
1960 }
1961 for( int i=0; i<NUM_ENTITIES; ++i ) {
1962 if ( entities[i].value == *q ) {
1963 Print( "&%s;", entities[i].pattern );
1964 break;
1965 }
1966 }
1967 ++p;
1968 }
1969 }
1970 ++q;
1971 }
1972 }
1973 // Flush the remaining string. This will be the entire
1974 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 Print( "%s", p );
1977 }
Lee Thomason857b8682012-01-25 17:50:25 -08001978}
1979
U-Stream\Leeae25a442012-02-17 17:48:16 -08001980
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001981void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001984 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 -07001985 Print( "%s", bom );
1986 }
1987 if ( writeDec ) {
1988 PushDeclaration( "xml version=\"1.0\"" );
1989 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001990}
1991
1992
Uli Kusterer593a33d2014-02-01 12:48:51 +01001993void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001994{
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 SealElement();
1997 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001998 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001999
Uli Kusterer593a33d2014-02-01 12:48:51 +01002000 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002002 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002003 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002006
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 _elementJustOpened = true;
2009 _firstElement = false;
2010 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002011}
2012
2013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002015{
Lee Thomason624d43f2012-10-12 10:58:48 -07002016 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 Print( " %s=\"", name );
2018 PrintString( value, false );
2019 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002020}
2021
2022
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002023void XMLPrinter::PushAttribute( const char* name, int v )
2024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 char buf[BUF_SIZE];
2026 XMLUtil::ToStr( v, buf, BUF_SIZE );
2027 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002028}
2029
2030
2031void XMLPrinter::PushAttribute( const char* name, unsigned v )
2032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 char buf[BUF_SIZE];
2034 XMLUtil::ToStr( v, buf, BUF_SIZE );
2035 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002036}
2037
2038
2039void XMLPrinter::PushAttribute( const char* name, bool v )
2040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 char buf[BUF_SIZE];
2042 XMLUtil::ToStr( v, buf, BUF_SIZE );
2043 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002044}
2045
2046
2047void XMLPrinter::PushAttribute( const char* name, double v )
2048{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 char buf[BUF_SIZE];
2050 XMLUtil::ToStr( v, buf, BUF_SIZE );
2051 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002052}
2053
2054
Uli Kustererca412e82014-02-01 13:35:05 +01002055void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002056{
Lee Thomason624d43f2012-10-12 10:58:48 -07002057 --_depth;
2058 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002059
Lee Thomason624d43f2012-10-12 10:58:48 -07002060 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 Print( "/>" );
2062 }
2063 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002064 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 }
2068 Print( "</%s>", name );
2069 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002070
Lee Thomason624d43f2012-10-12 10:58:48 -07002071 if ( _textDepth == _depth ) {
2072 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 }
Uli Kustererca412e82014-02-01 13:35:05 +01002074 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 Print( "\n" );
2076 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002078}
2079
2080
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002081void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002082{
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002085}
2086
2087
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002088void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002089{
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002091
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 SealElement();
2094 }
2095 if ( cdata ) {
2096 Print( "<![CDATA[" );
2097 Print( "%s", text );
2098 Print( "]]>" );
2099 }
2100 else {
2101 PrintString( text, true );
2102 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002103}
2104
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002105void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 char buf[BUF_SIZE];
2108 XMLUtil::ToStr( value, buf, BUF_SIZE );
2109 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002110}
2111
2112
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002113void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 char buf[BUF_SIZE];
2116 XMLUtil::ToStr( value, buf, BUF_SIZE );
2117 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002118}
2119
2120
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002121void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 char buf[BUF_SIZE];
2124 XMLUtil::ToStr( value, buf, BUF_SIZE );
2125 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002126}
2127
2128
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002129void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 char buf[BUF_SIZE];
2132 XMLUtil::ToStr( value, buf, BUF_SIZE );
2133 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002134}
2135
2136
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002137void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 char buf[BUF_SIZE];
2140 XMLUtil::ToStr( value, buf, BUF_SIZE );
2141 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002142}
2143
Lee Thomason5cae8972012-01-24 18:03:07 -08002144
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002145void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002146{
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 SealElement();
2149 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002156}
Lee Thomason751da522012-02-10 08:50:51 -08002157
2158
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002159void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002160{
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 SealElement();
2163 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002170}
2171
2172
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002173void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002174{
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 SealElement();
2177 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002184}
2185
2186
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002187bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002188{
Lee Thomason624d43f2012-10-12 10:58:48 -07002189 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 if ( doc.HasBOM() ) {
2191 PushHeader( true, false );
2192 }
2193 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002194}
2195
2196
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002197bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002198{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002199 const XMLElement* parentElem = element.Parent()->ToElement();
2200 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2201 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 while ( attribute ) {
2203 PushAttribute( attribute->Name(), attribute->Value() );
2204 attribute = attribute->Next();
2205 }
2206 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002207}
2208
2209
Uli Kustererca412e82014-02-01 13:35:05 +01002210bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002211{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002212 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002214}
2215
2216
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002217bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 PushText( text.Value(), text.CData() );
2220 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002221}
2222
2223
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002224bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 PushComment( comment.Value() );
2227 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002228}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002230bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 PushDeclaration( declaration.Value() );
2233 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 PushUnknown( unknown.Value() );
2240 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002242
Lee Thomason685b8952012-11-12 13:00:06 -08002243} // namespace tinyxml2
2244