blob: 9688e5dee266100d319c171811ed46e6437f3620 [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{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400117 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700118 return 0;
119 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800120
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400121 char* const start = p;
122
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{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400482 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 p = XMLUtil::SkipWhiteSpace( p );
484 if( !p || !*p ) {
485 return p;
486 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800489 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 static const char* xmlHeader = { "<?" };
491 static const char* commentHeader = { "<!--" };
492 static const char* dtdHeader = { "<!" };
493 static const char* cdataHeader = { "<![CDATA[" };
494 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800495
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 static const int xmlHeaderLen = 2;
497 static const int commentHeaderLen = 4;
498 static const int dtdHeaderLen = 2;
499 static const int cdataHeaderLen = 9;
500 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800502#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800503#pragma warning ( push )
504#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800505#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800508#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800509#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800510#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400511 XMLNode* returnNode = 0;
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;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400696 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 ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400826 *parentEnd = ele->_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 ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400836 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400838 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
840 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400841 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
843 else if ( !endTag.Empty() ) {
844 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400845 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 }
847 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400848 if ( mismatch ) {
849 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
850 p = 0;
851 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 }
853 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400854 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 node = 0;
856 }
857 if ( node ) {
858 this->InsertEndChild( node );
859 }
860 }
861 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800862}
863
Dmitry-Mee3225b12014-09-03 11:03:11 +0400864void XMLNode::DeleteNode( XMLNode* node )
865{
866 if ( node == 0 ) {
867 return;
868 }
869 MemPool* pool = node->_memPool;
870 node->~XMLNode();
871 pool->Free( node );
872}
873
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800875char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 const char* start = p;
878 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 return p;
884 }
885 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
887 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 flags |= StrPair::COLLAPSE_WHITESPACE;
889 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700890
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
895 if ( p && *p ) {
896 return p-1;
897 }
898 }
899 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900}
901
902
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800903XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
909 text->SetCData( this->CData() );
910 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
914bool XMLText::ShallowEqual( const XMLNode* compare ) const
915{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400916 const XMLText* text = compare->ToText();
917 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800918}
919
920
Lee Thomason56bdd022012-02-09 18:16:58 -0800921bool XMLText::Accept( XMLVisitor* visitor ) const
922{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800924}
925
926
Lee Thomason3f57d272012-01-11 15:30:03 -0800927// --------- XMLComment ---------- //
928
Lee Thomasone4422302012-01-20 17:59:50 -0800929XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800930{
931}
932
933
Lee Thomasonce0763e2012-01-11 15:43:54 -0800934XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800935{
Lee Thomason3f57d272012-01-11 15:30:03 -0800936}
937
938
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800939char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 // Comment parses as text.
942 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800948}
949
950
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
957 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958}
959
960
961bool XMLComment::ShallowEqual( const XMLNode* compare ) const
962{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400963 const XMLComment* comment = compare->ToComment();
964 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965}
966
967
Lee Thomason751da522012-02-10 08:50:51 -0800968bool XMLComment::Accept( XMLVisitor* visitor ) const
969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800971}
Lee Thomason56bdd022012-02-09 18:16:58 -0800972
973
Lee Thomason50f97b22012-02-11 16:33:40 -0800974// --------- XMLDeclaration ---------- //
975
976XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
977{
978}
979
980
981XMLDeclaration::~XMLDeclaration()
982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800984}
985
986
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800987char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // Declaration parses as text.
990 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800996}
997
998
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 }
1004 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1005 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001006}
1007
1008
1009bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1010{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001011 const XMLDeclaration* declaration = compare->ToDeclaration();
1012 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001013}
1014
1015
1016
Lee Thomason50f97b22012-02-11 16:33:40 -08001017bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1018{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001020}
1021
1022// --------- XMLUnknown ---------- //
1023
1024XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1025{
1026}
1027
1028
1029XMLUnknown::~XMLUnknown()
1030{
1031}
1032
1033
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001034char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 // Unknown parses as text.
1037 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001038
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001041 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 }
1043 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001044}
1045
1046
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001047XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1048{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 }
1052 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1053 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054}
1055
1056
1057bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1058{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001059 const XMLUnknown* unknown = compare->ToUnknown();
1060 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001061}
1062
1063
Lee Thomason50f97b22012-02-11 16:33:40 -08001064bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001067}
1068
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001069// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001070
1071const char* XMLAttribute::Name() const
1072{
1073 return _name.GetStr();
1074}
1075
1076const char* XMLAttribute::Value() const
1077{
1078 return _value.GetStr();
1079}
1080
Lee Thomason6f381b72012-03-02 12:59:39 -08001081char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( !p || !*p ) {
1086 return 0;
1087 }
Lee Thomason22aead12012-01-23 13:29:35 -08001088
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 // Skip white space before =
1090 p = XMLUtil::SkipWhiteSpace( p );
1091 if ( !p || *p != '=' ) {
1092 return 0;
1093 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001094
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 ++p; // move up to opening quote
1096 p = XMLUtil::SkipWhiteSpace( p );
1097 if ( *p != '\"' && *p != '\'' ) {
1098 return 0;
1099 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 char endTag[2] = { *p, 0 };
1102 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001103
Lee Thomason624d43f2012-10-12 10:58:48 -07001104 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001106}
1107
1108
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109void XMLAttribute::SetName( const char* n )
1110{
Lee Thomason624d43f2012-10-12 10:58:48 -07001111 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001112}
1113
1114
Lee Thomason2fa81722012-11-09 12:37:46 -08001115XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 if ( XMLUtil::ToInt( Value(), value )) {
1118 return XML_NO_ERROR;
1119 }
1120 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001121}
1122
1123
Lee Thomason2fa81722012-11-09 12:37:46 -08001124XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( XMLUtil::ToUnsigned( Value(), value )) {
1127 return XML_NO_ERROR;
1128 }
1129 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130}
1131
1132
Lee Thomason2fa81722012-11-09 12:37:46 -08001133XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( XMLUtil::ToBool( Value(), value )) {
1136 return XML_NO_ERROR;
1137 }
1138 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139}
1140
1141
Lee Thomason2fa81722012-11-09 12:37:46 -08001142XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 if ( XMLUtil::ToFloat( Value(), value )) {
1145 return XML_NO_ERROR;
1146 }
1147 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001148}
1149
1150
Lee Thomason2fa81722012-11-09 12:37:46 -08001151XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( XMLUtil::ToDouble( Value(), value )) {
1154 return XML_NO_ERROR;
1155 }
1156 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001157}
1158
1159
1160void XMLAttribute::SetAttribute( const char* v )
1161{
Lee Thomason624d43f2012-10-12 10:58:48 -07001162 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163}
1164
1165
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166void XMLAttribute::SetAttribute( int v )
1167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 char buf[BUF_SIZE];
1169 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001170 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001172
1173
1174void XMLAttribute::SetAttribute( unsigned v )
1175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 char buf[BUF_SIZE];
1177 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001178 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001179}
1180
1181
1182void XMLAttribute::SetAttribute( bool v )
1183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 char buf[BUF_SIZE];
1185 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001187}
1188
1189void XMLAttribute::SetAttribute( double v )
1190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 char buf[BUF_SIZE];
1192 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001193 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001194}
1195
1196void XMLAttribute::SetAttribute( float v )
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 char buf[BUF_SIZE];
1199 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001200 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001201}
1202
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001203
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001204// --------- XMLElement ---------- //
1205XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 _closingType( 0 ),
1207 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001208{
1209}
1210
1211
1212XMLElement::~XMLElement()
1213{
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 while( _rootAttribute ) {
1215 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001216 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001219}
1220
1221
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001222XMLAttribute* XMLElement::FindAttribute( const char* name )
1223{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001224 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1226 return a;
1227 }
1228 }
1229 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001230}
1231
1232
1233const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1234{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001235 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1237 return a;
1238 }
1239 }
1240 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241}
1242
1243
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001244const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 const XMLAttribute* a = FindAttribute( name );
1247 if ( !a ) {
1248 return 0;
1249 }
1250 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1251 return a->Value();
1252 }
1253 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001254}
1255
1256
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001257const char* XMLElement::GetText() const
1258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 if ( FirstChild() && FirstChild()->ToText() ) {
1260 return FirstChild()->ToText()->Value();
1261 }
1262 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001263}
1264
1265
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001266void XMLElement::SetText( const char* inText )
1267{
Uli Kusterer869bb592014-01-21 01:36:16 +01001268 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001269 FirstChild()->SetValue( inText );
1270 else {
1271 XMLText* theText = GetDocument()->NewText( inText );
1272 InsertFirstChild( theText );
1273 }
1274}
1275
Lee Thomason5bb2d802014-01-24 10:42:57 -08001276
1277void XMLElement::SetText( int v )
1278{
1279 char buf[BUF_SIZE];
1280 XMLUtil::ToStr( v, buf, BUF_SIZE );
1281 SetText( buf );
1282}
1283
1284
1285void XMLElement::SetText( unsigned v )
1286{
1287 char buf[BUF_SIZE];
1288 XMLUtil::ToStr( v, buf, BUF_SIZE );
1289 SetText( buf );
1290}
1291
1292
1293void XMLElement::SetText( bool v )
1294{
1295 char buf[BUF_SIZE];
1296 XMLUtil::ToStr( v, buf, BUF_SIZE );
1297 SetText( buf );
1298}
1299
1300
1301void XMLElement::SetText( float v )
1302{
1303 char buf[BUF_SIZE];
1304 XMLUtil::ToStr( v, buf, BUF_SIZE );
1305 SetText( buf );
1306}
1307
1308
1309void XMLElement::SetText( double v )
1310{
1311 char buf[BUF_SIZE];
1312 XMLUtil::ToStr( v, buf, BUF_SIZE );
1313 SetText( buf );
1314}
1315
1316
MortenMacFly4ee49f12013-01-14 20:03:14 +01001317XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( FirstChild() && FirstChild()->ToText() ) {
1320 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001321 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 return XML_SUCCESS;
1323 }
1324 return XML_CAN_NOT_CONVERT_TEXT;
1325 }
1326 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001327}
1328
1329
MortenMacFly4ee49f12013-01-14 20:03:14 +01001330XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( FirstChild() && FirstChild()->ToText() ) {
1333 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001334 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 return XML_SUCCESS;
1336 }
1337 return XML_CAN_NOT_CONVERT_TEXT;
1338 }
1339 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001340}
1341
1342
MortenMacFly4ee49f12013-01-14 20:03:14 +01001343XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( FirstChild() && FirstChild()->ToText() ) {
1346 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001347 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 return XML_SUCCESS;
1349 }
1350 return XML_CAN_NOT_CONVERT_TEXT;
1351 }
1352 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
1359 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
1372 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
1382
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001383XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 XMLAttribute* last = 0;
1386 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001387 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001389 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1391 break;
1392 }
1393 }
1394 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1396 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001404 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 }
1406 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407}
1408
1409
U-Stream\Leeae25a442012-02-17 17:48:16 -08001410void XMLElement::DeleteAttribute( const char* name )
1411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1415 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
1418 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001421 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 break;
1423 }
1424 prev = a;
1425 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001426}
1427
1428
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001429char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 const char* start = p;
1432 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001433
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 // Read the attributes.
1435 while( p ) {
1436 p = XMLUtil::SkipWhiteSpace( p );
1437 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 return 0;
1440 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001441
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001443 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1445 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001446 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001447
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001450 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 return 0;
1453 }
1454 // There is a minor bug here: if the attribute in the source xml
1455 // document is duplicated, it will not be detected and the
1456 // attribute will be doubly added. However, tracking the 'prevAttribute'
1457 // avoids re-scanning the attribute list. Preferring performance for
1458 // now, may reconsider in the future.
1459 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
1465 prevAttribute = attrib;
1466 }
1467 // end of the tag
1468 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 return p+2; // done; sealed element.
1471 }
1472 // end of the tag
1473 else if ( *p == '>' ) {
1474 ++p;
1475 break;
1476 }
1477 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return 0;
1480 }
1481 }
1482 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001483}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001484
Dmitry-Mee3225b12014-09-03 11:03:11 +04001485void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1486{
1487 if ( attribute == 0 ) {
1488 return;
1489 }
1490 MemPool* pool = attribute->_memPool;
1491 attribute->~XMLAttribute();
1492 pool->Free( attribute );
1493}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001494
Lee Thomason67d61312012-01-24 16:01:51 -08001495//
1496// <ele></ele>
1497// <ele>foo<b>bar</b></ele>
1498//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001499char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 // Read the element name.
1502 p = XMLUtil::SkipWhiteSpace( p );
1503 if ( !p ) {
1504 return 0;
1505 }
Lee Thomason67d61312012-01-24 16:01:51 -08001506
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 // The closing element is the </element> form. It is
1508 // parsed just like a regular element then deleted from
1509 // the DOM.
1510 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 ++p;
1513 }
Lee Thomason67d61312012-01-24 16:01:51 -08001514
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 p = _value.ParseName( p );
1516 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 return 0;
1518 }
Lee Thomason67d61312012-01-24 16:01:51 -08001519
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001521 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 return p;
1523 }
Lee Thomason67d61312012-01-24 16:01:51 -08001524
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 p = XMLNode::ParseDeep( p, strPair );
1526 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001527}
1528
1529
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001530
1531XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001534 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 }
1536 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1537 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1538 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1539 }
1540 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001541}
1542
1543
1544bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 const XMLElement* other = compare->ToElement();
1547 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 const XMLAttribute* a=FirstAttribute();
1550 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001551
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 while ( a && b ) {
1553 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1554 return false;
1555 }
1556 a = a->Next();
1557 b = b->Next();
1558 }
1559 if ( a || b ) {
1560 // different count
1561 return false;
1562 }
1563 return true;
1564 }
1565 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001566}
1567
1568
Lee Thomason751da522012-02-10 08:50:51 -08001569bool XMLElement::Accept( XMLVisitor* visitor ) const
1570{
Lee Thomason624d43f2012-10-12 10:58:48 -07001571 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1573 if ( !node->Accept( visitor ) ) {
1574 break;
1575 }
1576 }
1577 }
1578 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001579}
Lee Thomason56bdd022012-02-09 18:16:58 -08001580
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001581
Lee Thomason3f57d272012-01-11 15:30:03 -08001582// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001583
1584// Warning: List must match 'enum XMLError'
1585const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1586 "XML_SUCCESS",
1587 "XML_NO_ATTRIBUTE",
1588 "XML_WRONG_ATTRIBUTE_TYPE",
1589 "XML_ERROR_FILE_NOT_FOUND",
1590 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1591 "XML_ERROR_FILE_READ_ERROR",
1592 "XML_ERROR_ELEMENT_MISMATCH",
1593 "XML_ERROR_PARSING_ELEMENT",
1594 "XML_ERROR_PARSING_ATTRIBUTE",
1595 "XML_ERROR_IDENTIFYING_TAG",
1596 "XML_ERROR_PARSING_TEXT",
1597 "XML_ERROR_PARSING_CDATA",
1598 "XML_ERROR_PARSING_COMMENT",
1599 "XML_ERROR_PARSING_DECLARATION",
1600 "XML_ERROR_PARSING_UNKNOWN",
1601 "XML_ERROR_EMPTY_DOCUMENT",
1602 "XML_ERROR_MISMATCHED_ELEMENT",
1603 "XML_ERROR_PARSING",
1604 "XML_CAN_NOT_CONVERT_TEXT",
1605 "XML_NO_TEXT_NODE"
1606};
1607
1608
Lee Thomason624d43f2012-10-12 10:58:48 -07001609XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 _writeBOM( false ),
1612 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001613 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 _whitespace( whitespace ),
1615 _errorStr1( 0 ),
1616 _errorStr2( 0 ),
1617 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001618{
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001620}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001621
1622
Lee Thomason3f57d272012-01-11 15:30:03 -08001623XMLDocument::~XMLDocument()
1624{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001627
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001628#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001629 _textPool.Trace( "text" );
1630 _elementPool.Trace( "element" );
1631 _commentPool.Trace( "comment" );
1632 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001633#endif
1634
Lee Thomason5b0a6772012-11-19 13:54:42 -08001635#ifdef DEBUG
1636 if ( Error() == false ) {
1637 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1638 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1639 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1640 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1641 }
1642#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001643}
1644
1645
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001646void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001647{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001648 DeleteChildren();
1649
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _errorID = XML_NO_ERROR;
1651 _errorStr1 = 0;
1652 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001653
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 delete [] _charBuffer;
1655 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001656}
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658
Lee Thomason2c85a712012-01-31 08:24:24 -08001659XMLElement* XMLDocument::NewElement( const char* name )
1660{
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1662 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 ele->SetName( name );
1664 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001665}
1666
1667
Lee Thomason1ff38e02012-02-14 18:18:16 -08001668XMLComment* XMLDocument::NewComment( const char* str )
1669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1671 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 comment->SetValue( str );
1673 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001674}
1675
1676
1677XMLText* XMLDocument::NewText( const char* str )
1678{
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1680 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 text->SetValue( str );
1682 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001683}
1684
1685
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001686XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1687{
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1689 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1691 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001692}
1693
1694
1695XMLUnknown* XMLDocument::NewUnknown( const char* str )
1696{
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1698 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 unk->SetValue( str );
1700 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001701}
1702
Dmitry-Me01578db2014-08-19 10:18:48 +04001703static FILE* callfopen( const char* filepath, const char* mode )
1704{
1705#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1706 FILE* fp = 0;
1707 errno_t err = fopen_s( &fp, filepath, mode );
1708 if ( err ) {
1709 return 0;
1710 }
1711#else
1712 FILE* fp = fopen( filepath, mode );
1713#endif
1714 return fp;
1715}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001716
Lee Thomason2fa81722012-11-09 12:37:46 -08001717XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001718{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001719 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001720 FILE* fp = callfopen( filename, "rb" );
1721 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
1725 LoadFile( fp );
1726 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728}
1729
1730
Lee Thomason2fa81722012-11-09 12:37:46 -08001731XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001732{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001733 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001734
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001735 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001736 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001737 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1738 return _errorID;
1739 }
1740
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001742 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001744 if ( filelength == -1L ) {
1745 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1746 return _errorID;
1747 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001748
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001749 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001751 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001754
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 _charBuffer = new char[size+1];
1756 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 if ( read != size ) {
1758 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001761
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001763
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 if ( !p || !*p ) {
1768 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001771
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1773 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001774}
1775
1776
Lee Thomason2fa81722012-11-09 12:37:46 -08001777XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001778{
Dmitry-Me01578db2014-08-19 10:18:48 +04001779 FILE* fp = callfopen( filename, "w" );
1780 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
1784 SaveFile(fp, compact);
1785 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001787}
1788
1789
Lee Thomason2fa81722012-11-09 12:37:46 -08001790XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001791{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 XMLPrinter stream( fp, compact );
1793 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795}
1796
Lee Thomason1ff38e02012-02-14 18:18:16 -08001797
Lee Thomason2fa81722012-11-09 12:37:46 -08001798XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001799{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001800 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001801 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001802
Lee Thomason82d32002014-02-21 22:47:18 -08001803 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
1807 if ( len == (size_t)(-1) ) {
1808 len = strlen( p );
1809 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 _charBuffer = new char[ len+1 ];
1811 memcpy( _charBuffer, p, len );
1812 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001813
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 if ( !p || !*p ) {
1817 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001820
Thomas Roß1470edc2013-05-10 15:44:12 +02001821 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001822 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001824}
1825
1826
PKEuS1c5f99e2013-07-06 11:28:39 +02001827void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001828{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 XMLPrinter stdStreamer( stdout );
1830 if ( !streamer ) {
1831 streamer = &stdStreamer;
1832 }
1833 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001834}
1835
1836
Lee Thomason2fa81722012-11-09 12:37:46 -08001837void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001838{
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _errorID = error;
1840 _errorStr1 = str1;
1841 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001842}
1843
Lee Thomason331596e2014-09-11 14:56:43 -07001844const char* XMLDocument::ErrorName() const
1845{
1846 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1847 return _errorNames[_errorID];
1848}
Lee Thomason5cae8972012-01-24 18:03:07 -08001849
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001850void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001851{
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 static const int LEN = 20;
1854 char buf1[LEN] = { 0 };
1855 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001856
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 if ( _errorStr1 ) {
1858 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 if ( _errorStr2 ) {
1861 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001863
Lee Thomason331596e2014-09-11 14:56:43 -07001864 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1865 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001867}
1868
1869
PKEuS1bfb9542013-08-04 13:51:17 +02001870XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 _elementJustOpened( false ),
1872 _firstElement( true ),
1873 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001874 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _textDepth( -1 ),
1876 _processEntities( true ),
1877 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 _entityFlag[i] = false;
1881 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 }
1883 for( int i=0; i<NUM_ENTITIES; ++i ) {
1884 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1885 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 }
1888 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001889 _restrictedEntityFlag[(int)'&'] = true;
1890 _restrictedEntityFlag[(int)'<'] = true;
1891 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1892 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001893}
1894
1895
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001896void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001897{
1898 va_list va;
1899 va_start( va, format );
1900
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 if ( _fp ) {
1902 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 }
1904 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001905#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001906 #if defined(WINCE)
1907 int len = 512;
1908 do {
1909 len = len*2;
1910 char* str = new char[len]();
1911 len = _vsnprintf(str, len, format, va);
1912 delete[] str;
1913 }while (len < 0);
1914 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001915 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001916 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917#else
1918 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001919#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 // Close out and re-start the va-args
1921 va_end( va );
1922 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001923 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1924#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001925 #if defined(WINCE)
1926 _vsnprintf( p, len+1, format, va );
1927 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001928 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001929 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001930#else
1931 vsnprintf( p, len+1, format, va );
1932#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001934 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001935}
1936
1937
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001938void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 for( int i=0; i<depth; ++i ) {
1941 Print( " " );
1942 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001943}
1944
1945
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001946void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 // Look for runs of bytes between entities to print.
1949 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001951
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 while ( *q ) {
1954 // Remember, char is sometimes signed. (How many times has that bitten me?)
1955 if ( *q > 0 && *q < ENTITY_RANGE ) {
1956 // Check for entities. If one is found, flush
1957 // the stream up until the entity, write the
1958 // entity, and keep looking.
1959 if ( flag[(unsigned)(*q)] ) {
1960 while ( p < q ) {
1961 Print( "%c", *p );
1962 ++p;
1963 }
1964 for( int i=0; i<NUM_ENTITIES; ++i ) {
1965 if ( entities[i].value == *q ) {
1966 Print( "&%s;", entities[i].pattern );
1967 break;
1968 }
1969 }
1970 ++p;
1971 }
1972 }
1973 ++q;
1974 }
1975 }
1976 // Flush the remaining string. This will be the entire
1977 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 Print( "%s", p );
1980 }
Lee Thomason857b8682012-01-25 17:50:25 -08001981}
1982
U-Stream\Leeae25a442012-02-17 17:48:16 -08001983
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001984void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001987 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 -07001988 Print( "%s", bom );
1989 }
1990 if ( writeDec ) {
1991 PushDeclaration( "xml version=\"1.0\"" );
1992 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001993}
1994
1995
Uli Kusterer593a33d2014-02-01 12:48:51 +01001996void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001997{
Lee Thomason624d43f2012-10-12 10:58:48 -07001998 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 SealElement();
2000 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002002
Uli Kusterer593a33d2014-02-01 12:48:51 +01002003 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002005 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002006 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002009
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 _elementJustOpened = true;
2012 _firstElement = false;
2013 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002014}
2015
2016
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002017void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002018{
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 Print( " %s=\"", name );
2021 PrintString( value, false );
2022 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002023}
2024
2025
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002026void XMLPrinter::PushAttribute( const char* name, int v )
2027{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 char buf[BUF_SIZE];
2029 XMLUtil::ToStr( v, buf, BUF_SIZE );
2030 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002031}
2032
2033
2034void XMLPrinter::PushAttribute( const char* name, unsigned v )
2035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 char buf[BUF_SIZE];
2037 XMLUtil::ToStr( v, buf, BUF_SIZE );
2038 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002039}
2040
2041
2042void XMLPrinter::PushAttribute( const char* name, bool v )
2043{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 char buf[BUF_SIZE];
2045 XMLUtil::ToStr( v, buf, BUF_SIZE );
2046 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002047}
2048
2049
2050void XMLPrinter::PushAttribute( const char* name, double v )
2051{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 char buf[BUF_SIZE];
2053 XMLUtil::ToStr( v, buf, BUF_SIZE );
2054 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002055}
2056
2057
Uli Kustererca412e82014-02-01 13:35:05 +01002058void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002059{
Lee Thomason624d43f2012-10-12 10:58:48 -07002060 --_depth;
2061 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002062
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 Print( "/>" );
2065 }
2066 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002067 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 }
2071 Print( "</%s>", name );
2072 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002073
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 if ( _textDepth == _depth ) {
2075 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 }
Uli Kustererca412e82014-02-01 13:35:05 +01002077 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 Print( "\n" );
2079 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002081}
2082
2083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002085{
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002088}
2089
2090
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002091void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002092{
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002094
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 SealElement();
2097 }
2098 if ( cdata ) {
2099 Print( "<![CDATA[" );
2100 Print( "%s", text );
2101 Print( "]]>" );
2102 }
2103 else {
2104 PrintString( text, true );
2105 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002106}
2107
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002108void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 char buf[BUF_SIZE];
2111 XMLUtil::ToStr( value, buf, BUF_SIZE );
2112 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002113}
2114
2115
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002116void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 char buf[BUF_SIZE];
2119 XMLUtil::ToStr( value, buf, BUF_SIZE );
2120 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002121}
2122
2123
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002124void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 char buf[BUF_SIZE];
2127 XMLUtil::ToStr( value, buf, BUF_SIZE );
2128 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002129}
2130
2131
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002132void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 char buf[BUF_SIZE];
2135 XMLUtil::ToStr( value, buf, BUF_SIZE );
2136 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002137}
2138
2139
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002140void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 char buf[BUF_SIZE];
2143 XMLUtil::ToStr( value, buf, BUF_SIZE );
2144 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002145}
2146
Lee Thomason5cae8972012-01-24 18:03:07 -08002147
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002148void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002149{
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 SealElement();
2152 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002159}
Lee Thomason751da522012-02-10 08:50:51 -08002160
2161
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002162void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002163{
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 SealElement();
2166 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002173}
2174
2175
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002176void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002177{
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 SealElement();
2180 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187}
2188
2189
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002190bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002191{
Lee Thomason624d43f2012-10-12 10:58:48 -07002192 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 if ( doc.HasBOM() ) {
2194 PushHeader( true, false );
2195 }
2196 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002197}
2198
2199
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002200bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002201{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002202 const XMLElement* parentElem = element.Parent()->ToElement();
2203 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2204 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 while ( attribute ) {
2206 PushAttribute( attribute->Name(), attribute->Value() );
2207 attribute = attribute->Next();
2208 }
2209 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002210}
2211
2212
Uli Kustererca412e82014-02-01 13:35:05 +01002213bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002214{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002215 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002217}
2218
2219
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002220bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 PushText( text.Value(), text.CData() );
2223 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002224}
2225
2226
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002227bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 PushComment( comment.Value() );
2230 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002231}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002233bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 PushDeclaration( declaration.Value() );
2236 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 PushUnknown( unknown.Value() );
2243 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002245
Lee Thomason685b8952012-11-12 13:00:06 -08002246} // namespace tinyxml2
2247