blob: ae1c8a93fb9297bb6265a85621e6d464e79a1e30 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
73void StrPair::Reset()
74{
Lee Thomason120b3a62012-10-12 10:06:59 -070075 if ( _flags & NEEDS_DELETE ) {
76 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070077 }
Lee Thomason120b3a62012-10-12 10:06:59 -070078 _flags = 0;
79 _start = 0;
80 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081}
82
83
84void StrPair::SetStr( const char* str, int flags )
85{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070086 Reset();
87 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -070088 _start = new char[ len+1 ];
89 memcpy( _start, str, len+1 );
90 _end = _start + len;
91 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080092}
93
94
95char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
96{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070097 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080098
Dmitry-Meec19a0e2014-08-25 11:05:55 +040099 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 char endChar = *endTag;
101 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800102
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700103 // Inner loop of text parsing.
104 while ( *p ) {
105 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
106 Set( start, p, strFlags );
107 return p + length;
108 }
109 ++p;
110 }
111 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800112}
113
114
115char* StrPair::ParseName( char* p )
116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700117 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 if ( !start || !(*start) ) {
120 return 0;
121 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800122
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200123 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700124 ++p;
125 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700127 if ( p > start ) {
128 Set( start, p, 0 );
129 return p;
130 }
131 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800132}
133
134
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700135void StrPair::CollapseWhitespace()
136{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400137 // Adjusting _start would cause undefined behavior on delete[]
138 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700140 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700141
Lee Thomason120b3a62012-10-12 10:06:59 -0700142 if ( _start && *_start ) {
143 char* p = _start; // the read pointer
144 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700145
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700146 while( *p ) {
147 if ( XMLUtil::IsWhiteSpace( *p )) {
148 p = XMLUtil::SkipWhiteSpace( p );
149 if ( *p == 0 ) {
150 break; // don't write to q; this trims the trailing space.
151 }
152 *q = ' ';
153 ++q;
154 }
155 *q = *p;
156 ++q;
157 ++p;
158 }
159 *q = 0;
160 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161}
162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163
Lee Thomasone4422302012-01-20 17:59:50 -0800164const char* StrPair::GetStr()
165{
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 if ( _flags & NEEDS_FLUSH ) {
167 *_end = 0;
168 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800169
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags ) {
171 char* p = _start; // the read pointer
172 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800173
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 while( p < _end ) {
175 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700176 // CR-LF pair becomes LF
177 // CR alone becomes LF
178 // LF-CR becomes LF
179 if ( *(p+1) == LF ) {
180 p += 2;
181 }
182 else {
183 ++p;
184 }
185 *q++ = LF;
186 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700187 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700188 if ( *(p+1) == CR ) {
189 p += 2;
190 }
191 else {
192 ++p;
193 }
194 *q++ = LF;
195 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700196 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // Entities handled by tinyXML2:
198 // - special entities in the entity table [in/out]
199 // - numeric character reference [in]
200 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400203 const int buflen = 10;
204 char buf[buflen] = { 0 };
205 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400207 TIXMLASSERT( 0 <= len && len <= buflen );
208 TIXMLASSERT( q + len <= p );
209 memcpy( q, buf, len );
210 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 }
212 else {
213 int i=0;
214 for(; i<NUM_ENTITIES; ++i ) {
215 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
216 && *(p+entities[i].length+1) == ';' ) {
217 // Found an entity convert;
218 *q = entities[i].value;
219 ++q;
220 p += entities[i].length + 2;
221 break;
222 }
223 }
224 if ( i == NUM_ENTITIES ) {
225 // fixme: treat as error?
226 ++p;
227 ++q;
228 }
229 }
230 }
231 else {
232 *q = *p;
233 ++p;
234 ++q;
235 }
236 }
237 *q = 0;
238 }
239 // The loop below has plenty going on, and this
240 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 CollapseWhitespace();
243 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700244 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800247}
248
Lee Thomason2c85a712012-01-31 08:24:24 -0800249
Lee Thomasone4422302012-01-20 17:59:50 -0800250
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800251
Lee Thomason56bdd022012-02-09 18:16:58 -0800252// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800253
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800254const char* XMLUtil::ReadBOM( const char* p, bool* bom )
255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 *bom = false;
257 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
258 // Check for BOM:
259 if ( *(pu+0) == TIXML_UTF_LEAD_0
260 && *(pu+1) == TIXML_UTF_LEAD_1
261 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
262 *bom = true;
263 p += 3;
264 }
265 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266}
267
268
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800269void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 const unsigned long BYTE_MASK = 0xBF;
272 const unsigned long BYTE_MARK = 0x80;
273 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800274
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 if (input < 0x80) {
276 *length = 1;
277 }
278 else if ( input < 0x800 ) {
279 *length = 2;
280 }
281 else if ( input < 0x10000 ) {
282 *length = 3;
283 }
284 else if ( input < 0x200000 ) {
285 *length = 4;
286 }
287 else {
288 *length = 0; // This code won't covert this correctly anyway.
289 return;
290 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 // Scary scary fall throughs.
295 switch (*length) {
296 case 4:
297 --output;
298 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
299 input >>= 6;
300 case 3:
301 --output;
302 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
303 input >>= 6;
304 case 2:
305 --output;
306 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
307 input >>= 6;
308 case 1:
309 --output;
310 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100311 default:
312 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800314}
315
316
317const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 // Presume an entity, and pull it out.
320 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 if ( *(p+1) == '#' && *(p+2) ) {
323 unsigned long ucs = 0;
324 ptrdiff_t delta = 0;
325 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800326
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 if ( *(p+2) == 'x' ) {
328 // Hexadecimal.
329 if ( !*(p+3) ) {
330 return 0;
331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 const char* q = p+3;
334 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800335
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 if ( !q || !*q ) {
337 return 0;
338 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 delta = q-p;
341 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 while ( *q != 'x' ) {
344 if ( *q >= '0' && *q <= '9' ) {
345 ucs += mult * (*q - '0');
346 }
347 else if ( *q >= 'a' && *q <= 'f' ) {
348 ucs += mult * (*q - 'a' + 10);
349 }
350 else if ( *q >= 'A' && *q <= 'F' ) {
351 ucs += mult * (*q - 'A' + 10 );
352 }
353 else {
354 return 0;
355 }
356 mult *= 16;
357 --q;
358 }
359 }
360 else {
361 // Decimal.
362 if ( !*(p+2) ) {
363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 const char* q = p+2;
367 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( !q || !*q ) {
370 return 0;
371 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != '#' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else {
381 return 0;
382 }
383 mult *= 10;
384 --q;
385 }
386 }
387 // convert the UCS to UTF-8
388 ConvertUTF32ToUTF8( ucs, value, length );
389 return p + delta + 1;
390 }
391 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800393
394
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700395void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700398}
399
400
401void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700404}
405
406
407void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700410}
411
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800412/*
413 ToStr() of a number is a very tricky topic.
414 https://github.com/leethomason/tinyxml2/issues/106
415*/
Lee Thomason21be8822012-07-15 17:27:22 -0700416void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
417{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800418 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
423{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800424 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428bool XMLUtil::ToInt( const char* str, int* value )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
431 return true;
432 }
433 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
439 return true;
440 }
441 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700442}
443
444bool XMLUtil::ToBool( const char* str, bool* value )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 int ival = 0;
447 if ( ToInt( str, &ival )) {
448 *value = (ival==0) ? false : true;
449 return true;
450 }
451 if ( StringEqual( str, "true" ) ) {
452 *value = true;
453 return true;
454 }
455 else if ( StringEqual( str, "false" ) ) {
456 *value = false;
457 return true;
458 }
459 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700460}
461
462
463bool XMLUtil::ToFloat( const char* str, float* value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToDouble( const char* str, double* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
474 return true;
475 }
476 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
479
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700480char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 XMLNode* returnNode = 0;
483 char* start = p;
484 p = XMLUtil::SkipWhiteSpace( p );
485 if( !p || !*p ) {
486 return p;
487 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800488
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800490 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 static const char* xmlHeader = { "<?" };
492 static const char* commentHeader = { "<!--" };
493 static const char* dtdHeader = { "<!" };
494 static const char* cdataHeader = { "<![CDATA[" };
495 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 static const int xmlHeaderLen = 2;
498 static const int commentHeaderLen = 4;
499 static const int dtdHeaderLen = 2;
500 static const int cdataHeaderLen = 9;
501 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800503#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800504#pragma warning ( push )
505#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800506#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
508 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800509#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800510#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700513 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
514 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 p += xmlHeaderLen;
516 }
517 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700518 returnNode = new (_commentPool.Alloc()) XMLComment( this );
519 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 p += commentHeaderLen;
521 }
522 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700523 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700525 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 p += cdataHeaderLen;
527 text->SetCData( true );
528 }
529 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700530 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
531 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p += dtdHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700535 returnNode = new (_elementPool.Alloc()) XMLElement( this );
536 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 p += elementHeaderLen;
538 }
539 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_textPool.Alloc()) XMLText( this );
541 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = start; // Back it up, all the text counts.
543 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 *node = returnNode;
546 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800547}
548
549
Lee Thomason751da522012-02-10 08:50:51 -0800550bool XMLDocument::Accept( XMLVisitor* visitor ) const
551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 if ( visitor->VisitEnter( *this ) ) {
553 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
554 if ( !node->Accept( visitor ) ) {
555 break;
556 }
557 }
558 }
559 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800560}
Lee Thomason56bdd022012-02-09 18:16:58 -0800561
562
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563// --------- XMLNode ----------- //
564
565XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 _document( doc ),
567 _parent( 0 ),
568 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200569 _prev( 0 ), _next( 0 ),
570 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800572}
573
574
575XMLNode::~XMLNode()
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700578 if ( _parent ) {
579 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800581}
582
Michael Daumling21626882013-10-22 17:03:37 +0200583const char* XMLNode::Value() const
584{
585 return _value.GetStr();
586}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800587
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800588void XMLNode::SetValue( const char* str, bool staticMem )
589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700591 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 }
593 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800596}
597
598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800599void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600{
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 while( _firstChild ) {
602 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700604
Dmitry-Mee3225b12014-09-03 11:03:11 +0400605 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800608}
609
610
611void XMLNode::Unlink( XMLNode* child )
612{
Lee Thomason624d43f2012-10-12 10:58:48 -0700613 if ( child == _firstChild ) {
614 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 if ( child == _lastChild ) {
617 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
Lee Thomasond923c672012-01-23 08:44:25 -0800619
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( child->_prev ) {
621 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 if ( child->_next ) {
624 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700626 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627}
628
629
U-Stream\Leeae25a442012-02-17 17:48:16 -0800630void XMLNode::DeleteChild( XMLNode* node )
631{
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400633 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800634}
635
636
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800637XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
638{
Michael Daumlinged523282013-10-23 07:47:29 +0200639 if (addThis->_document != _document)
640 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641
Michael Daumlinged523282013-10-23 07:47:29 +0200642 if (addThis->_parent)
643 addThis->_parent->Unlink( addThis );
644 else
645 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( _lastChild ) {
648 TIXMLASSERT( _firstChild );
649 TIXMLASSERT( _lastChild->_next == 0 );
650 _lastChild->_next = addThis;
651 addThis->_prev = _lastChild;
652 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 TIXMLASSERT( _firstChild == 0 );
658 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_prev = 0;
661 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665}
666
667
Lee Thomason1ff38e02012-02-14 18:18:16 -0800668XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
669{
Michael Daumlinged523282013-10-23 07:47:29 +0200670 if (addThis->_document != _document)
671 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700672
Michael Daumlinged523282013-10-23 07:47:29 +0200673 if (addThis->_parent)
674 addThis->_parent->Unlink( addThis );
675 else
676 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( _firstChild ) {
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 _firstChild->_prev = addThis;
683 addThis->_next = _firstChild;
684 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
688 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_prev = 0;
693 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Michael Daumlinged523282013-10-23 07:47:29 +0200702 if (addThis->_document != _document)
703 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 return 0;
709 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 // The last node or the only node.
713 return InsertEndChild( addThis );
714 }
Michael Daumlinged523282013-10-23 07:47:29 +0200715 if (addThis->_parent)
716 addThis->_parent->Unlink( addThis );
717 else
718 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = afterThis;
720 addThis->_next = afterThis->_next;
721 afterThis->_next->_prev = addThis;
722 afterThis->_next = addThis;
723 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725}
726
727
728
729
Lee Thomason56bdd022012-02-09 18:16:58 -0800730const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800731{
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 XMLElement* element = node->ToElement();
734 if ( element ) {
735 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
736 return element;
737 }
738 }
739 }
740 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800741}
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::LastChildElement( const char* value ) const
745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800755}
756
757
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800758const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
759{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400760 for( XMLNode* node=this->_next; node; node = node->_next ) {
761 const XMLElement* element = node->ToElement();
762 if ( element
763 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
764 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
771const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
772{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400773 for( XMLNode* node=_prev; node; node = node->_prev ) {
774 const XMLElement* element = node->ToElement();
775 if ( element
776 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
777 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // This is a recursive method, but thinking about it "at the current level"
787 // it is a pretty simple flat list:
788 // <foo/>
789 // <!-- comment -->
790 //
791 // With a special case:
792 // <foo>
793 // </foo>
794 // <!-- comment -->
795 //
796 // Where the closing element (/foo) *must* be the next thing after the opening
797 // element, and the names must match. BUT the tricky bit is that the closing
798 // element will be read by the child.
799 //
800 // 'endTag' is the end tag for this node, it is returned by a call to a child.
801 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800802
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 while( p && *p ) {
804 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 if ( p == 0 || node == 0 ) {
808 break;
809 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800810
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 StrPair endTag;
812 p = node->ParseDeep( p, &endTag );
813 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( !_document->Error() ) {
817 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 break;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400822 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400824 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800828 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400829 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 return p;
831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // Handle an end tag returned to this level.
834 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 if ( ele ) {
836 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 p = 0;
839 }
840 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 p = 0;
843 }
844 else if ( !endTag.Empty() ) {
845 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 p = 0;
848 }
849 }
850 }
851 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400852 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 node = 0;
854 }
855 if ( node ) {
856 this->InsertEndChild( node );
857 }
858 }
859 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800860}
861
Dmitry-Mee3225b12014-09-03 11:03:11 +0400862void XMLNode::DeleteNode( XMLNode* node )
863{
864 if ( node == 0 ) {
865 return;
866 }
867 MemPool* pool = node->_memPool;
868 node->~XMLNode();
869 pool->Free( node );
870}
871
Lee Thomason5492a1c2012-01-23 15:32:10 -0800872// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800873char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 const char* start = p;
876 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 return p;
882 }
883 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
885 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 flags |= StrPair::COLLAPSE_WHITESPACE;
887 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 }
893 if ( p && *p ) {
894 return p-1;
895 }
896 }
897 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800898}
899
900
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800901XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
902{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 }
906 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
907 text->SetCData( this->CData() );
908 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909}
910
911
912bool XMLText::ShallowEqual( const XMLNode* compare ) const
913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800915}
916
917
Lee Thomason56bdd022012-02-09 18:16:58 -0800918bool XMLText::Accept( XMLVisitor* visitor ) const
919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800921}
922
923
Lee Thomason3f57d272012-01-11 15:30:03 -0800924// --------- XMLComment ---------- //
925
Lee Thomasone4422302012-01-20 17:59:50 -0800926XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800927{
928}
929
930
Lee Thomasonce0763e2012-01-11 15:43:54 -0800931XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800932{
Lee Thomason3f57d272012-01-11 15:30:03 -0800933}
934
935
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800936char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 // Comment parses as text.
939 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800945}
946
947
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
954 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
958bool XMLComment::ShallowEqual( const XMLNode* compare ) const
959{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400960 const XMLComment* comment = compare->ToComment();
961 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800962}
963
964
Lee Thomason751da522012-02-10 08:50:51 -0800965bool XMLComment::Accept( XMLVisitor* visitor ) const
966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800968}
Lee Thomason56bdd022012-02-09 18:16:58 -0800969
970
Lee Thomason50f97b22012-02-11 16:33:40 -0800971// --------- XMLDeclaration ---------- //
972
973XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
974{
975}
976
977
978XMLDeclaration::~XMLDeclaration()
979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800981}
982
983
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800984char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 // Declaration parses as text.
987 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800993}
994
995
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1002 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001003}
1004
1005
1006bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1007{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLDeclaration* declaration = compare->ToDeclaration();
1009 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019// --------- XMLUnknown ---------- //
1020
1021XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLUnknown::~XMLUnknown()
1027{
1028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Unknown parses as text.
1034 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1050 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1055{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001056 const XMLUnknown* unknown = compare->ToUnknown();
1057 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001067
1068const char* XMLAttribute::Name() const
1069{
1070 return _name.GetStr();
1071}
1072
1073const char* XMLAttribute::Value() const
1074{
1075 return _value.GetStr();
1076}
1077
Lee Thomason6f381b72012-03-02 12:59:39 -08001078char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p || !*p ) {
1083 return 0;
1084 }
Lee Thomason22aead12012-01-23 13:29:35 -08001085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Skip white space before =
1087 p = XMLUtil::SkipWhiteSpace( p );
1088 if ( !p || *p != '=' ) {
1089 return 0;
1090 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 ++p; // move up to opening quote
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( *p != '\"' && *p != '\'' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 char endTag[2] = { *p, 0 };
1099 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106void XMLAttribute::SetName( const char* n )
1107{
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToInt( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
Lee Thomason2fa81722012-11-09 12:37:46 -08001121XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( XMLUtil::ToUnsigned( Value(), value )) {
1124 return XML_NO_ERROR;
1125 }
1126 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason2fa81722012-11-09 12:37:46 -08001130XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( XMLUtil::ToBool( Value(), value )) {
1133 return XML_NO_ERROR;
1134 }
1135 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToFloat( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToDouble( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
1157void XMLAttribute::SetAttribute( const char* v )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163void XMLAttribute::SetAttribute( int v )
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 char buf[BUF_SIZE];
1166 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169
1170
1171void XMLAttribute::SetAttribute( unsigned v )
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 char buf[BUF_SIZE];
1174 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001176}
1177
1178
1179void XMLAttribute::SetAttribute( bool v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186void XMLAttribute::SetAttribute( double v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193void XMLAttribute::SetAttribute( float v )
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char buf[BUF_SIZE];
1196 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001198}
1199
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001200
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001201// --------- XMLElement ---------- //
1202XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _closingType( 0 ),
1204 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205{
1206}
1207
1208
1209XMLElement::~XMLElement()
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 while( _rootAttribute ) {
1212 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001213 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001216}
1217
1218
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219XMLAttribute* XMLElement::FindAttribute( const char* name )
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1224 return a;
1225 }
1226 }
1227 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001228}
1229
1230
1231const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001234 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1236 return a;
1237 }
1238 }
1239 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001243const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 const XMLAttribute* a = FindAttribute( name );
1246 if ( !a ) {
1247 return 0;
1248 }
1249 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1250 return a->Value();
1251 }
1252 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001253}
1254
1255
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001256const char* XMLElement::GetText() const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( FirstChild() && FirstChild()->ToText() ) {
1259 return FirstChild()->ToText()->Value();
1260 }
1261 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262}
1263
1264
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001265void XMLElement::SetText( const char* inText )
1266{
Uli Kusterer869bb592014-01-21 01:36:16 +01001267 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001268 FirstChild()->SetValue( inText );
1269 else {
1270 XMLText* theText = GetDocument()->NewText( inText );
1271 InsertFirstChild( theText );
1272 }
1273}
1274
Lee Thomason5bb2d802014-01-24 10:42:57 -08001275
1276void XMLElement::SetText( int v )
1277{
1278 char buf[BUF_SIZE];
1279 XMLUtil::ToStr( v, buf, BUF_SIZE );
1280 SetText( buf );
1281}
1282
1283
1284void XMLElement::SetText( unsigned v )
1285{
1286 char buf[BUF_SIZE];
1287 XMLUtil::ToStr( v, buf, BUF_SIZE );
1288 SetText( buf );
1289}
1290
1291
1292void XMLElement::SetText( bool v )
1293{
1294 char buf[BUF_SIZE];
1295 XMLUtil::ToStr( v, buf, BUF_SIZE );
1296 SetText( buf );
1297}
1298
1299
1300void XMLElement::SetText( float v )
1301{
1302 char buf[BUF_SIZE];
1303 XMLUtil::ToStr( v, buf, BUF_SIZE );
1304 SetText( buf );
1305}
1306
1307
1308void XMLElement::SetText( double v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
MortenMacFly4ee49f12013-01-14 20:03:14 +01001316XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( FirstChild() && FirstChild()->ToText() ) {
1319 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001320 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 return XML_SUCCESS;
1322 }
1323 return XML_CAN_NOT_CONVERT_TEXT;
1324 }
1325 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001326}
1327
1328
MortenMacFly4ee49f12013-01-14 20:03:14 +01001329XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( FirstChild() && FirstChild()->ToText() ) {
1332 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001333 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 return XML_SUCCESS;
1335 }
1336 return XML_CAN_NOT_CONVERT_TEXT;
1337 }
1338 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001339}
1340
1341
MortenMacFly4ee49f12013-01-14 20:03:14 +01001342XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( FirstChild() && FirstChild()->ToText() ) {
1345 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001346 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 return XML_SUCCESS;
1348 }
1349 return XML_CAN_NOT_CONVERT_TEXT;
1350 }
1351 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001352}
1353
1354
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 if ( FirstChild() && FirstChild()->ToText() ) {
1358 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001359 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 return XML_SUCCESS;
1361 }
1362 return XML_CAN_NOT_CONVERT_TEXT;
1363 }
1364 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001365}
1366
1367
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( FirstChild() && FirstChild()->ToText() ) {
1371 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001372 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 return XML_SUCCESS;
1374 }
1375 return XML_CAN_NOT_CONVERT_TEXT;
1376 }
1377 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001378}
1379
1380
1381
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001382XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 XMLAttribute* last = 0;
1385 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1390 break;
1391 }
1392 }
1393 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1395 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001397 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 }
1399 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 }
1402 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001403 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001406}
1407
1408
U-Stream\Leeae25a442012-02-17 17:48:16 -08001409void XMLElement::DeleteAttribute( const char* name )
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1414 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001420 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 break;
1422 }
1423 prev = a;
1424 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001425}
1426
1427
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001428char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 const char* start = p;
1431 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001432
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 // Read the attributes.
1434 while( p ) {
1435 p = XMLUtil::SkipWhiteSpace( p );
1436 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 return 0;
1439 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001440
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001442 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1444 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001445 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001446
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001449 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 return 0;
1452 }
1453 // There is a minor bug here: if the attribute in the source xml
1454 // document is duplicated, it will not be detected and the
1455 // attribute will be doubly added. However, tracking the 'prevAttribute'
1456 // avoids re-scanning the attribute list. Preferring performance for
1457 // now, may reconsider in the future.
1458 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 prevAttribute = attrib;
1465 }
1466 // end of the tag
1467 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 return p+2; // done; sealed element.
1470 }
1471 // end of the tag
1472 else if ( *p == '>' ) {
1473 ++p;
1474 break;
1475 }
1476 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 return 0;
1479 }
1480 }
1481 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001482}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483
Dmitry-Mee3225b12014-09-03 11:03:11 +04001484void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1485{
1486 if ( attribute == 0 ) {
1487 return;
1488 }
1489 MemPool* pool = attribute->_memPool;
1490 attribute->~XMLAttribute();
1491 pool->Free( attribute );
1492}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001493
Lee Thomason67d61312012-01-24 16:01:51 -08001494//
1495// <ele></ele>
1496// <ele>foo<b>bar</b></ele>
1497//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001498char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 // Read the element name.
1501 p = XMLUtil::SkipWhiteSpace( p );
1502 if ( !p ) {
1503 return 0;
1504 }
Lee Thomason67d61312012-01-24 16:01:51 -08001505
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 // The closing element is the </element> form. It is
1507 // parsed just like a regular element then deleted from
1508 // the DOM.
1509 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 ++p;
1512 }
Lee Thomason67d61312012-01-24 16:01:51 -08001513
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 p = _value.ParseName( p );
1515 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 return 0;
1517 }
Lee Thomason67d61312012-01-24 16:01:51 -08001518
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return p;
1522 }
Lee Thomason67d61312012-01-24 16:01:51 -08001523
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 p = XMLNode::ParseDeep( p, strPair );
1525 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001526}
1527
1528
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001529
1530XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001533 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 }
1535 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1536 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1537 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1538 }
1539 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001540}
1541
1542
1543bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 const XMLElement* other = compare->ToElement();
1546 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 const XMLAttribute* a=FirstAttribute();
1549 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001550
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 while ( a && b ) {
1552 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1553 return false;
1554 }
1555 a = a->Next();
1556 b = b->Next();
1557 }
1558 if ( a || b ) {
1559 // different count
1560 return false;
1561 }
1562 return true;
1563 }
1564 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565}
1566
1567
Lee Thomason751da522012-02-10 08:50:51 -08001568bool XMLElement::Accept( XMLVisitor* visitor ) const
1569{
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1572 if ( !node->Accept( visitor ) ) {
1573 break;
1574 }
1575 }
1576 }
1577 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001578}
Lee Thomason56bdd022012-02-09 18:16:58 -08001579
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001580
Lee Thomason3f57d272012-01-11 15:30:03 -08001581// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001582XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 _writeBOM( false ),
1585 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001586 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001587 _whitespace( whitespace ),
1588 _errorStr1( 0 ),
1589 _errorStr2( 0 ),
1590 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001591{
Lee Thomason624d43f2012-10-12 10:58:48 -07001592 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001593}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001594
1595
Lee Thomason3f57d272012-01-11 15:30:03 -08001596XMLDocument::~XMLDocument()
1597{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001599 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001600
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001601#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001602 _textPool.Trace( "text" );
1603 _elementPool.Trace( "element" );
1604 _commentPool.Trace( "comment" );
1605 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001606#endif
1607
Lee Thomason5b0a6772012-11-19 13:54:42 -08001608#ifdef DEBUG
1609 if ( Error() == false ) {
1610 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1611 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1612 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1613 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1614 }
1615#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001616}
1617
1618
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001619void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001620{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001621 DeleteChildren();
1622
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 _errorID = XML_NO_ERROR;
1624 _errorStr1 = 0;
1625 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001626
Lee Thomason624d43f2012-10-12 10:58:48 -07001627 delete [] _charBuffer;
1628 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001629}
1630
Lee Thomason3f57d272012-01-11 15:30:03 -08001631
Lee Thomason2c85a712012-01-31 08:24:24 -08001632XMLElement* XMLDocument::NewElement( const char* name )
1633{
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1635 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 ele->SetName( name );
1637 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001638}
1639
1640
Lee Thomason1ff38e02012-02-14 18:18:16 -08001641XMLComment* XMLDocument::NewComment( const char* str )
1642{
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1644 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 comment->SetValue( str );
1646 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001647}
1648
1649
1650XMLText* XMLDocument::NewText( const char* str )
1651{
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1653 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 text->SetValue( str );
1655 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001656}
1657
1658
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001659XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1660{
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1662 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1664 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001665}
1666
1667
1668XMLUnknown* XMLDocument::NewUnknown( const char* str )
1669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1671 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 unk->SetValue( str );
1673 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001674}
1675
Dmitry-Me01578db2014-08-19 10:18:48 +04001676static FILE* callfopen( const char* filepath, const char* mode )
1677{
1678#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1679 FILE* fp = 0;
1680 errno_t err = fopen_s( &fp, filepath, mode );
1681 if ( err ) {
1682 return 0;
1683 }
1684#else
1685 FILE* fp = fopen( filepath, mode );
1686#endif
1687 return fp;
1688}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001689
Lee Thomason2fa81722012-11-09 12:37:46 -08001690XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001691{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001692 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001693 FILE* fp = callfopen( filename, "rb" );
1694 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 }
1698 LoadFile( fp );
1699 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001701}
1702
1703
Lee Thomason2fa81722012-11-09 12:37:46 -08001704XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001705{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001706 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001707
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001708 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001709 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001710 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1711 return _errorID;
1712 }
1713
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001715 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001717 if ( filelength == -1L ) {
1718 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1719 return _errorID;
1720 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001721
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001722 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001724 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001727
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 _charBuffer = new char[size+1];
1729 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 if ( read != size ) {
1731 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001734
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001736
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 if ( !p || !*p ) {
1741 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001744
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1746 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001747}
1748
1749
Lee Thomason2fa81722012-11-09 12:37:46 -08001750XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001751{
Dmitry-Me01578db2014-08-19 10:18:48 +04001752 FILE* fp = callfopen( filename, "w" );
1753 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 }
1757 SaveFile(fp, compact);
1758 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001760}
1761
1762
Lee Thomason2fa81722012-11-09 12:37:46 -08001763XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001764{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 XMLPrinter stream( fp, compact );
1766 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001768}
1769
Lee Thomason1ff38e02012-02-14 18:18:16 -08001770
Lee Thomason2fa81722012-11-09 12:37:46 -08001771XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001772{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001773 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001774 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001775
Lee Thomason82d32002014-02-21 22:47:18 -08001776 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 if ( len == (size_t)(-1) ) {
1781 len = strlen( p );
1782 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 _charBuffer = new char[ len+1 ];
1784 memcpy( _charBuffer, p, len );
1785 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001786
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( !p || !*p ) {
1790 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001793
Thomas Roß1470edc2013-05-10 15:44:12 +02001794 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001795 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001797}
1798
1799
PKEuS1c5f99e2013-07-06 11:28:39 +02001800void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001801{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 XMLPrinter stdStreamer( stdout );
1803 if ( !streamer ) {
1804 streamer = &stdStreamer;
1805 }
1806 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001807}
1808
1809
Lee Thomason2fa81722012-11-09 12:37:46 -08001810void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001811{
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 _errorID = error;
1813 _errorStr1 = str1;
1814 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001815}
1816
Lee Thomason5cae8972012-01-24 18:03:07 -08001817
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001818void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001819{
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 static const int LEN = 20;
1822 char buf1[LEN] = { 0 };
1823 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001824
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 if ( _errorStr1 ) {
1826 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 if ( _errorStr2 ) {
1829 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001831
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001835}
1836
1837
PKEuS1bfb9542013-08-04 13:51:17 +02001838XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _elementJustOpened( false ),
1840 _firstElement( true ),
1841 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001842 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _textDepth( -1 ),
1844 _processEntities( true ),
1845 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001846{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 _entityFlag[i] = false;
1849 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 }
1851 for( int i=0; i<NUM_ENTITIES; ++i ) {
1852 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1853 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 }
1856 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 _restrictedEntityFlag[(int)'&'] = true;
1858 _restrictedEntityFlag[(int)'<'] = true;
1859 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1860 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001861}
1862
1863
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001864void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001865{
1866 va_list va;
1867 va_start( va, format );
1868
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 if ( _fp ) {
1870 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 }
1872 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001873#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001874 #if defined(WINCE)
1875 int len = 512;
1876 do {
1877 len = len*2;
1878 char* str = new char[len]();
1879 len = _vsnprintf(str, len, format, va);
1880 delete[] str;
1881 }while (len < 0);
1882 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001883 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001884 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885#else
1886 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001887#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 // Close out and re-start the va-args
1889 va_end( va );
1890 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001891 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1892#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001893 #if defined(WINCE)
1894 _vsnprintf( p, len+1, format, va );
1895 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001896 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001897 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001898#else
1899 vsnprintf( p, len+1, format, va );
1900#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001902 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001903}
1904
1905
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001906void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 for( int i=0; i<depth; ++i ) {
1909 Print( " " );
1910 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001911}
1912
1913
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001914void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 // Look for runs of bytes between entities to print.
1917 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001919
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 while ( *q ) {
1922 // Remember, char is sometimes signed. (How many times has that bitten me?)
1923 if ( *q > 0 && *q < ENTITY_RANGE ) {
1924 // Check for entities. If one is found, flush
1925 // the stream up until the entity, write the
1926 // entity, and keep looking.
1927 if ( flag[(unsigned)(*q)] ) {
1928 while ( p < q ) {
1929 Print( "%c", *p );
1930 ++p;
1931 }
1932 for( int i=0; i<NUM_ENTITIES; ++i ) {
1933 if ( entities[i].value == *q ) {
1934 Print( "&%s;", entities[i].pattern );
1935 break;
1936 }
1937 }
1938 ++p;
1939 }
1940 }
1941 ++q;
1942 }
1943 }
1944 // Flush the remaining string. This will be the entire
1945 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 Print( "%s", p );
1948 }
Lee Thomason857b8682012-01-25 17:50:25 -08001949}
1950
U-Stream\Leeae25a442012-02-17 17:48:16 -08001951
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001952void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001955 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 -07001956 Print( "%s", bom );
1957 }
1958 if ( writeDec ) {
1959 PushDeclaration( "xml version=\"1.0\"" );
1960 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001961}
1962
1963
Uli Kusterer593a33d2014-02-01 12:48:51 +01001964void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001965{
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 SealElement();
1968 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001970
Uli Kusterer593a33d2014-02-01 12:48:51 +01001971 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001973 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001974 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001977
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 _elementJustOpened = true;
1980 _firstElement = false;
1981 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001982}
1983
1984
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001985void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001986{
Lee Thomason624d43f2012-10-12 10:58:48 -07001987 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 Print( " %s=\"", name );
1989 PrintString( value, false );
1990 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001991}
1992
1993
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001994void XMLPrinter::PushAttribute( const char* name, int v )
1995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 char buf[BUF_SIZE];
1997 XMLUtil::ToStr( v, buf, BUF_SIZE );
1998 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001999}
2000
2001
2002void XMLPrinter::PushAttribute( const char* name, unsigned v )
2003{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 char buf[BUF_SIZE];
2005 XMLUtil::ToStr( v, buf, BUF_SIZE );
2006 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002007}
2008
2009
2010void XMLPrinter::PushAttribute( const char* name, bool v )
2011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 char buf[BUF_SIZE];
2013 XMLUtil::ToStr( v, buf, BUF_SIZE );
2014 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002015}
2016
2017
2018void XMLPrinter::PushAttribute( const char* name, double v )
2019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 char buf[BUF_SIZE];
2021 XMLUtil::ToStr( v, buf, BUF_SIZE );
2022 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002023}
2024
2025
Uli Kustererca412e82014-02-01 13:35:05 +01002026void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002027{
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 --_depth;
2029 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002030
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 Print( "/>" );
2033 }
2034 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002035 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
2039 Print( "</%s>", name );
2040 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002041
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 if ( _textDepth == _depth ) {
2043 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 }
Uli Kustererca412e82014-02-01 13:35:05 +01002045 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 Print( "\n" );
2047 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002049}
2050
2051
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002052void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002053{
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002056}
2057
2058
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002059void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002060{
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002062
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 SealElement();
2065 }
2066 if ( cdata ) {
2067 Print( "<![CDATA[" );
2068 Print( "%s", text );
2069 Print( "]]>" );
2070 }
2071 else {
2072 PrintString( text, true );
2073 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002074}
2075
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002076void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 char buf[BUF_SIZE];
2079 XMLUtil::ToStr( value, buf, BUF_SIZE );
2080 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002081}
2082
2083
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002084void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 char buf[BUF_SIZE];
2087 XMLUtil::ToStr( value, buf, BUF_SIZE );
2088 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002089}
2090
2091
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002092void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 char buf[BUF_SIZE];
2095 XMLUtil::ToStr( value, buf, BUF_SIZE );
2096 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002097}
2098
2099
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002100void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 char buf[BUF_SIZE];
2103 XMLUtil::ToStr( value, buf, BUF_SIZE );
2104 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002105}
2106
2107
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002108void XMLPrinter::PushText( double 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
Lee Thomason5cae8972012-01-24 18:03:07 -08002115
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002116void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002117{
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 SealElement();
2120 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002127}
Lee Thomason751da522012-02-10 08:50:51 -08002128
2129
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002130void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002131{
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 SealElement();
2134 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002141}
2142
2143
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002144void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002145{
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 SealElement();
2148 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002153 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002155}
2156
2157
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002158bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002159{
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 if ( doc.HasBOM() ) {
2162 PushHeader( true, false );
2163 }
2164 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002165}
2166
2167
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002168bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002169{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002170 const XMLElement* parentElem = element.Parent()->ToElement();
2171 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2172 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 while ( attribute ) {
2174 PushAttribute( attribute->Name(), attribute->Value() );
2175 attribute = attribute->Next();
2176 }
2177 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002178}
2179
2180
Uli Kustererca412e82014-02-01 13:35:05 +01002181bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002182{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002183 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002185}
2186
2187
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002188bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 PushText( text.Value(), text.CData() );
2191 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002192}
2193
2194
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002195bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 PushComment( comment.Value() );
2198 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002199}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002200
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002201bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 PushDeclaration( declaration.Value() );
2204 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002205}
2206
2207
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002208bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 PushUnknown( unknown.Value() );
2211 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002212}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002213
Lee Thomason685b8952012-11-12 13:00:06 -08002214} // namespace tinyxml2
2215