blob: 9e310dee87ccbab919e0de59b0ba931ce51bb38a [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
73void StrPair::Reset()
74{
Lee Thomason120b3a62012-10-12 10:06:59 -070075 if ( _flags & NEEDS_DELETE ) {
76 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070077 }
Lee Thomason120b3a62012-10-12 10:06:59 -070078 _flags = 0;
79 _start = 0;
80 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081}
82
83
84void StrPair::SetStr( const char* str, int flags )
85{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070086 Reset();
87 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -070088 _start = new char[ len+1 ];
89 memcpy( _start, str, len+1 );
90 _end = _start + len;
91 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080092}
93
94
95char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
96{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070097 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080098
Dmitry-Meec19a0e2014-08-25 11:05:55 +040099 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 char endChar = *endTag;
101 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800102
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700103 // Inner loop of text parsing.
104 while ( *p ) {
105 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
106 Set( start, p, strFlags );
107 return p + length;
108 }
109 ++p;
110 }
111 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800112}
113
114
115char* StrPair::ParseName( char* p )
116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700117 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 if ( !start || !(*start) ) {
120 return 0;
121 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800122
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200123 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700124 ++p;
125 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700127 if ( p > start ) {
128 Set( start, p, 0 );
129 return p;
130 }
131 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800132}
133
134
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700135void StrPair::CollapseWhitespace()
136{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400137 // Adjusting _start would cause undefined behavior on delete[]
138 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700140 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700141
Lee Thomason120b3a62012-10-12 10:06:59 -0700142 if ( _start && *_start ) {
143 char* p = _start; // the read pointer
144 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700145
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700146 while( *p ) {
147 if ( XMLUtil::IsWhiteSpace( *p )) {
148 p = XMLUtil::SkipWhiteSpace( p );
149 if ( *p == 0 ) {
150 break; // don't write to q; this trims the trailing space.
151 }
152 *q = ' ';
153 ++q;
154 }
155 *q = *p;
156 ++q;
157 ++p;
158 }
159 *q = 0;
160 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161}
162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163
Lee Thomasone4422302012-01-20 17:59:50 -0800164const char* StrPair::GetStr()
165{
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 if ( _flags & NEEDS_FLUSH ) {
167 *_end = 0;
168 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800169
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags ) {
171 char* p = _start; // the read pointer
172 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800173
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 while( p < _end ) {
175 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700176 // CR-LF pair becomes LF
177 // CR alone becomes LF
178 // LF-CR becomes LF
179 if ( *(p+1) == LF ) {
180 p += 2;
181 }
182 else {
183 ++p;
184 }
185 *q++ = LF;
186 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700187 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700188 if ( *(p+1) == CR ) {
189 p += 2;
190 }
191 else {
192 ++p;
193 }
194 *q++ = LF;
195 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700196 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // Entities handled by tinyXML2:
198 // - special entities in the entity table [in/out]
199 // - numeric character reference [in]
200 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400203 const int buflen = 10;
204 char buf[buflen] = { 0 };
205 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400207 TIXMLASSERT( 0 <= len && len <= buflen );
208 TIXMLASSERT( q + len <= p );
209 memcpy( q, buf, len );
210 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 }
212 else {
213 int i=0;
214 for(; i<NUM_ENTITIES; ++i ) {
215 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
216 && *(p+entities[i].length+1) == ';' ) {
217 // Found an entity convert;
218 *q = entities[i].value;
219 ++q;
220 p += entities[i].length + 2;
221 break;
222 }
223 }
224 if ( i == NUM_ENTITIES ) {
225 // fixme: treat as error?
226 ++p;
227 ++q;
228 }
229 }
230 }
231 else {
232 *q = *p;
233 ++p;
234 ++q;
235 }
236 }
237 *q = 0;
238 }
239 // The loop below has plenty going on, and this
240 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 CollapseWhitespace();
243 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700244 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800247}
248
Lee Thomason2c85a712012-01-31 08:24:24 -0800249
Lee Thomasone4422302012-01-20 17:59:50 -0800250
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800251
Lee Thomason56bdd022012-02-09 18:16:58 -0800252// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800253
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800254const char* XMLUtil::ReadBOM( const char* p, bool* bom )
255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 *bom = false;
257 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
258 // Check for BOM:
259 if ( *(pu+0) == TIXML_UTF_LEAD_0
260 && *(pu+1) == TIXML_UTF_LEAD_1
261 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
262 *bom = true;
263 p += 3;
264 }
265 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266}
267
268
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800269void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 const unsigned long BYTE_MASK = 0xBF;
272 const unsigned long BYTE_MARK = 0x80;
273 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800274
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 if (input < 0x80) {
276 *length = 1;
277 }
278 else if ( input < 0x800 ) {
279 *length = 2;
280 }
281 else if ( input < 0x10000 ) {
282 *length = 3;
283 }
284 else if ( input < 0x200000 ) {
285 *length = 4;
286 }
287 else {
288 *length = 0; // This code won't covert this correctly anyway.
289 return;
290 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 // Scary scary fall throughs.
295 switch (*length) {
296 case 4:
297 --output;
298 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
299 input >>= 6;
300 case 3:
301 --output;
302 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
303 input >>= 6;
304 case 2:
305 --output;
306 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
307 input >>= 6;
308 case 1:
309 --output;
310 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100311 default:
312 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800314}
315
316
317const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 // Presume an entity, and pull it out.
320 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 if ( *(p+1) == '#' && *(p+2) ) {
323 unsigned long ucs = 0;
324 ptrdiff_t delta = 0;
325 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800326
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 if ( *(p+2) == 'x' ) {
328 // Hexadecimal.
329 if ( !*(p+3) ) {
330 return 0;
331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 const char* q = p+3;
334 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800335
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 if ( !q || !*q ) {
337 return 0;
338 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 delta = q-p;
341 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 while ( *q != 'x' ) {
344 if ( *q >= '0' && *q <= '9' ) {
345 ucs += mult * (*q - '0');
346 }
347 else if ( *q >= 'a' && *q <= 'f' ) {
348 ucs += mult * (*q - 'a' + 10);
349 }
350 else if ( *q >= 'A' && *q <= 'F' ) {
351 ucs += mult * (*q - 'A' + 10 );
352 }
353 else {
354 return 0;
355 }
356 mult *= 16;
357 --q;
358 }
359 }
360 else {
361 // Decimal.
362 if ( !*(p+2) ) {
363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 const char* q = p+2;
367 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( !q || !*q ) {
370 return 0;
371 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != '#' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else {
381 return 0;
382 }
383 mult *= 10;
384 --q;
385 }
386 }
387 // convert the UCS to UTF-8
388 ConvertUTF32ToUTF8( ucs, value, length );
389 return p + delta + 1;
390 }
391 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800393
394
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700395void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700398}
399
400
401void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700404}
405
406
407void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700410}
411
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800412/*
413 ToStr() of a number is a very tricky topic.
414 https://github.com/leethomason/tinyxml2/issues/106
415*/
Lee Thomason21be8822012-07-15 17:27:22 -0700416void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
417{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800418 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
423{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800424 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428bool XMLUtil::ToInt( const char* str, int* value )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
431 return true;
432 }
433 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
439 return true;
440 }
441 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700442}
443
444bool XMLUtil::ToBool( const char* str, bool* value )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 int ival = 0;
447 if ( ToInt( str, &ival )) {
448 *value = (ival==0) ? false : true;
449 return true;
450 }
451 if ( StringEqual( str, "true" ) ) {
452 *value = true;
453 return true;
454 }
455 else if ( StringEqual( str, "false" ) ) {
456 *value = false;
457 return true;
458 }
459 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700460}
461
462
463bool XMLUtil::ToFloat( const char* str, float* value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToDouble( const char* str, double* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
474 return true;
475 }
476 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
479
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700480char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 XMLNode* returnNode = 0;
483 char* start = p;
484 p = XMLUtil::SkipWhiteSpace( p );
485 if( !p || !*p ) {
486 return p;
487 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800488
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800490 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 static const char* xmlHeader = { "<?" };
492 static const char* commentHeader = { "<!--" };
493 static const char* dtdHeader = { "<!" };
494 static const char* cdataHeader = { "<![CDATA[" };
495 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 static const int xmlHeaderLen = 2;
498 static const int commentHeaderLen = 4;
499 static const int dtdHeaderLen = 2;
500 static const int cdataHeaderLen = 9;
501 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800503#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800504#pragma warning ( push )
505#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800506#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
508 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800509#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800510#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700513 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
514 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 p += xmlHeaderLen;
516 }
517 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700518 returnNode = new (_commentPool.Alloc()) XMLComment( this );
519 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 p += commentHeaderLen;
521 }
522 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700523 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700525 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 p += cdataHeaderLen;
527 text->SetCData( true );
528 }
529 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700530 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
531 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p += dtdHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700535 returnNode = new (_elementPool.Alloc()) XMLElement( this );
536 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 p += elementHeaderLen;
538 }
539 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_textPool.Alloc()) XMLText( this );
541 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = start; // Back it up, all the text counts.
543 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 *node = returnNode;
546 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800547}
548
549
Lee Thomason751da522012-02-10 08:50:51 -0800550bool XMLDocument::Accept( XMLVisitor* visitor ) const
551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 if ( visitor->VisitEnter( *this ) ) {
553 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
554 if ( !node->Accept( visitor ) ) {
555 break;
556 }
557 }
558 }
559 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800560}
Lee Thomason56bdd022012-02-09 18:16:58 -0800561
562
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563// --------- XMLNode ----------- //
564
565XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 _document( doc ),
567 _parent( 0 ),
568 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200569 _prev( 0 ), _next( 0 ),
570 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800572}
573
574
575XMLNode::~XMLNode()
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700578 if ( _parent ) {
579 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800581}
582
Michael Daumling21626882013-10-22 17:03:37 +0200583const char* XMLNode::Value() const
584{
585 return _value.GetStr();
586}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800587
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800588void XMLNode::SetValue( const char* str, bool staticMem )
589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700591 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 }
593 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800596}
597
598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800599void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600{
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 while( _firstChild ) {
602 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700604
Dmitry-Mee3225b12014-09-03 11:03:11 +0400605 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800608}
609
610
611void XMLNode::Unlink( XMLNode* child )
612{
Lee Thomason624d43f2012-10-12 10:58:48 -0700613 if ( child == _firstChild ) {
614 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 if ( child == _lastChild ) {
617 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
Lee Thomasond923c672012-01-23 08:44:25 -0800619
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( child->_prev ) {
621 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 if ( child->_next ) {
624 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700626 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627}
628
629
U-Stream\Leeae25a442012-02-17 17:48:16 -0800630void XMLNode::DeleteChild( XMLNode* node )
631{
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400633 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800634}
635
636
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800637XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
638{
Michael Daumlinged523282013-10-23 07:47:29 +0200639 if (addThis->_document != _document)
640 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641
Michael Daumlinged523282013-10-23 07:47:29 +0200642 if (addThis->_parent)
643 addThis->_parent->Unlink( addThis );
644 else
645 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( _lastChild ) {
648 TIXMLASSERT( _firstChild );
649 TIXMLASSERT( _lastChild->_next == 0 );
650 _lastChild->_next = addThis;
651 addThis->_prev = _lastChild;
652 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 TIXMLASSERT( _firstChild == 0 );
658 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_prev = 0;
661 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665}
666
667
Lee Thomason1ff38e02012-02-14 18:18:16 -0800668XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
669{
Michael Daumlinged523282013-10-23 07:47:29 +0200670 if (addThis->_document != _document)
671 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700672
Michael Daumlinged523282013-10-23 07:47:29 +0200673 if (addThis->_parent)
674 addThis->_parent->Unlink( addThis );
675 else
676 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( _firstChild ) {
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 _firstChild->_prev = addThis;
683 addThis->_next = _firstChild;
684 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
688 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_prev = 0;
693 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Michael Daumlinged523282013-10-23 07:47:29 +0200702 if (addThis->_document != _document)
703 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 return 0;
709 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 // The last node or the only node.
713 return InsertEndChild( addThis );
714 }
Michael Daumlinged523282013-10-23 07:47:29 +0200715 if (addThis->_parent)
716 addThis->_parent->Unlink( addThis );
717 else
718 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = afterThis;
720 addThis->_next = afterThis->_next;
721 afterThis->_next->_prev = addThis;
722 afterThis->_next = addThis;
723 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725}
726
727
728
729
Lee Thomason56bdd022012-02-09 18:16:58 -0800730const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800731{
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 XMLElement* element = node->ToElement();
734 if ( element ) {
735 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
736 return element;
737 }
738 }
739 }
740 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800741}
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::LastChildElement( const char* value ) const
745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800755}
756
757
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800758const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
759{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400760 for( XMLNode* node=this->_next; node; node = node->_next ) {
761 const XMLElement* element = node->ToElement();
762 if ( element
763 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
764 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
771const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
772{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400773 for( XMLNode* node=_prev; node; node = node->_prev ) {
774 const XMLElement* element = node->ToElement();
775 if ( element
776 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
777 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // This is a recursive method, but thinking about it "at the current level"
787 // it is a pretty simple flat list:
788 // <foo/>
789 // <!-- comment -->
790 //
791 // With a special case:
792 // <foo>
793 // </foo>
794 // <!-- comment -->
795 //
796 // Where the closing element (/foo) *must* be the next thing after the opening
797 // element, and the names must match. BUT the tricky bit is that the closing
798 // element will be read by the child.
799 //
800 // 'endTag' is the end tag for this node, it is returned by a call to a child.
801 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800802
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 while( p && *p ) {
804 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 if ( p == 0 || node == 0 ) {
808 break;
809 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800810
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 StrPair endTag;
812 p = node->ParseDeep( p, &endTag );
813 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( !_document->Error() ) {
817 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 break;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400822 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400824 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800828 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400829 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 return p;
831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // Handle an end tag returned to this level.
834 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 if ( ele ) {
836 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 p = 0;
839 }
840 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 p = 0;
843 }
844 else if ( !endTag.Empty() ) {
845 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 p = 0;
848 }
849 }
850 }
851 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400852 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 node = 0;
854 }
855 if ( node ) {
856 this->InsertEndChild( node );
857 }
858 }
859 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800860}
861
Dmitry-Mee3225b12014-09-03 11:03:11 +0400862void XMLNode::DeleteNode( XMLNode* node )
863{
864 if ( node == 0 ) {
865 return;
866 }
867 MemPool* pool = node->_memPool;
868 node->~XMLNode();
869 pool->Free( node );
870}
871
Lee Thomason5492a1c2012-01-23 15:32:10 -0800872// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800873char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 const char* start = p;
876 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 return p;
882 }
883 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
885 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 flags |= StrPair::COLLAPSE_WHITESPACE;
887 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 }
893 if ( p && *p ) {
894 return p-1;
895 }
896 }
897 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800898}
899
900
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800901XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
902{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 }
906 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
907 text->SetCData( this->CData() );
908 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800909}
910
911
912bool XMLText::ShallowEqual( const XMLNode* compare ) const
913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800915}
916
917
Lee Thomason56bdd022012-02-09 18:16:58 -0800918bool XMLText::Accept( XMLVisitor* visitor ) const
919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800921}
922
923
Lee Thomason3f57d272012-01-11 15:30:03 -0800924// --------- XMLComment ---------- //
925
Lee Thomasone4422302012-01-20 17:59:50 -0800926XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800927{
928}
929
930
Lee Thomasonce0763e2012-01-11 15:43:54 -0800931XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800932{
Lee Thomason3f57d272012-01-11 15:30:03 -0800933}
934
935
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800936char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 // Comment parses as text.
939 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800945}
946
947
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700951 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
954 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
958bool XMLComment::ShallowEqual( const XMLNode* compare ) const
959{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400960 const XMLComment* comment = compare->ToComment();
961 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800962}
963
964
Lee Thomason751da522012-02-10 08:50:51 -0800965bool XMLComment::Accept( XMLVisitor* visitor ) const
966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800968}
Lee Thomason56bdd022012-02-09 18:16:58 -0800969
970
Lee Thomason50f97b22012-02-11 16:33:40 -0800971// --------- XMLDeclaration ---------- //
972
973XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
974{
975}
976
977
978XMLDeclaration::~XMLDeclaration()
979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800981}
982
983
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800984char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 // Declaration parses as text.
987 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800993}
994
995
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1002 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001003}
1004
1005
1006bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1007{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLDeclaration* declaration = compare->ToDeclaration();
1009 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019// --------- XMLUnknown ---------- //
1020
1021XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLUnknown::~XMLUnknown()
1027{
1028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Unknown parses as text.
1034 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1050 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1055{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001056 const XMLUnknown* unknown = compare->ToUnknown();
1057 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001067
1068const char* XMLAttribute::Name() const
1069{
1070 return _name.GetStr();
1071}
1072
1073const char* XMLAttribute::Value() const
1074{
1075 return _value.GetStr();
1076}
1077
Lee Thomason6f381b72012-03-02 12:59:39 -08001078char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p || !*p ) {
1083 return 0;
1084 }
Lee Thomason22aead12012-01-23 13:29:35 -08001085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Skip white space before =
1087 p = XMLUtil::SkipWhiteSpace( p );
1088 if ( !p || *p != '=' ) {
1089 return 0;
1090 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 ++p; // move up to opening quote
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( *p != '\"' && *p != '\'' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 char endTag[2] = { *p, 0 };
1099 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106void XMLAttribute::SetName( const char* n )
1107{
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToInt( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
Lee Thomason2fa81722012-11-09 12:37:46 -08001121XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( XMLUtil::ToUnsigned( Value(), value )) {
1124 return XML_NO_ERROR;
1125 }
1126 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason2fa81722012-11-09 12:37:46 -08001130XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( XMLUtil::ToBool( Value(), value )) {
1133 return XML_NO_ERROR;
1134 }
1135 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToFloat( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToDouble( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
1157void XMLAttribute::SetAttribute( const char* v )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163void XMLAttribute::SetAttribute( int v )
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 char buf[BUF_SIZE];
1166 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169
1170
1171void XMLAttribute::SetAttribute( unsigned v )
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 char buf[BUF_SIZE];
1174 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001176}
1177
1178
1179void XMLAttribute::SetAttribute( bool v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186void XMLAttribute::SetAttribute( double v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193void XMLAttribute::SetAttribute( float v )
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char buf[BUF_SIZE];
1196 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001198}
1199
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001200
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001201// --------- XMLElement ---------- //
1202XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _closingType( 0 ),
1204 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205{
1206}
1207
1208
1209XMLElement::~XMLElement()
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 while( _rootAttribute ) {
1212 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001213 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001216}
1217
1218
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219XMLAttribute* XMLElement::FindAttribute( const char* name )
1220{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001221 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1223 return a;
1224 }
1225 }
1226 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227}
1228
1229
1230const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1231{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001232 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1234 return a;
1235 }
1236 }
1237 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001241const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 const XMLAttribute* a = FindAttribute( name );
1244 if ( !a ) {
1245 return 0;
1246 }
1247 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1248 return a->Value();
1249 }
1250 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001251}
1252
1253
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001254const char* XMLElement::GetText() const
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 return FirstChild()->ToText()->Value();
1258 }
1259 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001260}
1261
1262
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001263void XMLElement::SetText( const char* inText )
1264{
Uli Kusterer869bb592014-01-21 01:36:16 +01001265 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001266 FirstChild()->SetValue( inText );
1267 else {
1268 XMLText* theText = GetDocument()->NewText( inText );
1269 InsertFirstChild( theText );
1270 }
1271}
1272
Lee Thomason5bb2d802014-01-24 10:42:57 -08001273
1274void XMLElement::SetText( int v )
1275{
1276 char buf[BUF_SIZE];
1277 XMLUtil::ToStr( v, buf, BUF_SIZE );
1278 SetText( buf );
1279}
1280
1281
1282void XMLElement::SetText( unsigned v )
1283{
1284 char buf[BUF_SIZE];
1285 XMLUtil::ToStr( v, buf, BUF_SIZE );
1286 SetText( buf );
1287}
1288
1289
1290void XMLElement::SetText( bool v )
1291{
1292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1294 SetText( buf );
1295}
1296
1297
1298void XMLElement::SetText( float v )
1299{
1300 char buf[BUF_SIZE];
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1302 SetText( buf );
1303}
1304
1305
1306void XMLElement::SetText( double v )
1307{
1308 char buf[BUF_SIZE];
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1310 SetText( buf );
1311}
1312
1313
MortenMacFly4ee49f12013-01-14 20:03:14 +01001314XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( FirstChild() && FirstChild()->ToText() ) {
1317 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001318 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return XML_SUCCESS;
1320 }
1321 return XML_CAN_NOT_CONVERT_TEXT;
1322 }
1323 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001324}
1325
1326
MortenMacFly4ee49f12013-01-14 20:03:14 +01001327XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( FirstChild() && FirstChild()->ToText() ) {
1330 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001331 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 return XML_SUCCESS;
1333 }
1334 return XML_CAN_NOT_CONVERT_TEXT;
1335 }
1336 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001337}
1338
1339
MortenMacFly4ee49f12013-01-14 20:03:14 +01001340XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( FirstChild() && FirstChild()->ToText() ) {
1343 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001344 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 return XML_SUCCESS;
1346 }
1347 return XML_CAN_NOT_CONVERT_TEXT;
1348 }
1349 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001350}
1351
1352
MortenMacFly4ee49f12013-01-14 20:03:14 +01001353XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( FirstChild() && FirstChild()->ToText() ) {
1356 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return XML_SUCCESS;
1359 }
1360 return XML_CAN_NOT_CONVERT_TEXT;
1361 }
1362 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001363}
1364
1365
MortenMacFly4ee49f12013-01-14 20:03:14 +01001366XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001367{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 if ( FirstChild() && FirstChild()->ToText() ) {
1369 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 return XML_SUCCESS;
1372 }
1373 return XML_CAN_NOT_CONVERT_TEXT;
1374 }
1375 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001376}
1377
1378
1379
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001380XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 XMLAttribute* last = 0;
1383 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001384 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1388 break;
1389 }
1390 }
1391 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1393 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 }
1397 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001401 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001404}
1405
1406
U-Stream\Leeae25a442012-02-17 17:48:16 -08001407void XMLElement::DeleteAttribute( const char* name )
1408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1412 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 }
1415 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001418 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 break;
1420 }
1421 prev = a;
1422 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001423}
1424
1425
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001426char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 const char* start = p;
1429 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001430
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 // Read the attributes.
1432 while( p ) {
1433 p = XMLUtil::SkipWhiteSpace( p );
1434 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 return 0;
1437 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001440 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001441 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1442 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001443 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001444
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001447 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 return 0;
1450 }
1451 // There is a minor bug here: if the attribute in the source xml
1452 // document is duplicated, it will not be detected and the
1453 // attribute will be doubly added. However, tracking the 'prevAttribute'
1454 // avoids re-scanning the attribute list. Preferring performance for
1455 // now, may reconsider in the future.
1456 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 prevAttribute = attrib;
1463 }
1464 // end of the tag
1465 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 return p+2; // done; sealed element.
1468 }
1469 // end of the tag
1470 else if ( *p == '>' ) {
1471 ++p;
1472 break;
1473 }
1474 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 return 0;
1477 }
1478 }
1479 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001480}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481
Dmitry-Mee3225b12014-09-03 11:03:11 +04001482void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1483{
1484 if ( attribute == 0 ) {
1485 return;
1486 }
1487 MemPool* pool = attribute->_memPool;
1488 attribute->~XMLAttribute();
1489 pool->Free( attribute );
1490}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491
Lee Thomason67d61312012-01-24 16:01:51 -08001492//
1493// <ele></ele>
1494// <ele>foo<b>bar</b></ele>
1495//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001496char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 // Read the element name.
1499 p = XMLUtil::SkipWhiteSpace( p );
1500 if ( !p ) {
1501 return 0;
1502 }
Lee Thomason67d61312012-01-24 16:01:51 -08001503
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 // The closing element is the </element> form. It is
1505 // parsed just like a regular element then deleted from
1506 // the DOM.
1507 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 ++p;
1510 }
Lee Thomason67d61312012-01-24 16:01:51 -08001511
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 p = _value.ParseName( p );
1513 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
Lee Thomason67d61312012-01-24 16:01:51 -08001516
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 return p;
1520 }
Lee Thomason67d61312012-01-24 16:01:51 -08001521
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 p = XMLNode::ParseDeep( p, strPair );
1523 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001524}
1525
1526
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001527
1528XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 }
1533 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1534 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1535 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1536 }
1537 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001538}
1539
1540
1541bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1542{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 const XMLElement* other = compare->ToElement();
1544 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001545
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 const XMLAttribute* a=FirstAttribute();
1547 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 while ( a && b ) {
1550 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1551 return false;
1552 }
1553 a = a->Next();
1554 b = b->Next();
1555 }
1556 if ( a || b ) {
1557 // different count
1558 return false;
1559 }
1560 return true;
1561 }
1562 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563}
1564
1565
Lee Thomason751da522012-02-10 08:50:51 -08001566bool XMLElement::Accept( XMLVisitor* visitor ) const
1567{
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1570 if ( !node->Accept( visitor ) ) {
1571 break;
1572 }
1573 }
1574 }
1575 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001576}
Lee Thomason56bdd022012-02-09 18:16:58 -08001577
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578
Lee Thomason3f57d272012-01-11 15:30:03 -08001579// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001580XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001582 _writeBOM( false ),
1583 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001584 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001585 _whitespace( whitespace ),
1586 _errorStr1( 0 ),
1587 _errorStr2( 0 ),
1588 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001589{
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001591}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001592
1593
Lee Thomason3f57d272012-01-11 15:30:03 -08001594XMLDocument::~XMLDocument()
1595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001597 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001598
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001599#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001600 _textPool.Trace( "text" );
1601 _elementPool.Trace( "element" );
1602 _commentPool.Trace( "comment" );
1603 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001604#endif
1605
Lee Thomason5b0a6772012-11-19 13:54:42 -08001606#ifdef DEBUG
1607 if ( Error() == false ) {
1608 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1609 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1610 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1611 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1612 }
1613#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001614}
1615
1616
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001617void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001618{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001619 DeleteChildren();
1620
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 _errorID = XML_NO_ERROR;
1622 _errorStr1 = 0;
1623 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001624
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 delete [] _charBuffer;
1626 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001627}
1628
Lee Thomason3f57d272012-01-11 15:30:03 -08001629
Lee Thomason2c85a712012-01-31 08:24:24 -08001630XMLElement* XMLDocument::NewElement( const char* name )
1631{
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1633 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 ele->SetName( name );
1635 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001636}
1637
1638
Lee Thomason1ff38e02012-02-14 18:18:16 -08001639XMLComment* XMLDocument::NewComment( const char* str )
1640{
Lee Thomason624d43f2012-10-12 10:58:48 -07001641 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1642 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 comment->SetValue( str );
1644 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001645}
1646
1647
1648XMLText* XMLDocument::NewText( const char* str )
1649{
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1651 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 text->SetValue( str );
1653 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001654}
1655
1656
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001657XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1658{
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1660 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1662 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001663}
1664
1665
1666XMLUnknown* XMLDocument::NewUnknown( const char* str )
1667{
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1669 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 unk->SetValue( str );
1671 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001672}
1673
Dmitry-Me01578db2014-08-19 10:18:48 +04001674static FILE* callfopen( const char* filepath, const char* mode )
1675{
1676#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1677 FILE* fp = 0;
1678 errno_t err = fopen_s( &fp, filepath, mode );
1679 if ( err ) {
1680 return 0;
1681 }
1682#else
1683 FILE* fp = fopen( filepath, mode );
1684#endif
1685 return fp;
1686}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001687
Lee Thomason2fa81722012-11-09 12:37:46 -08001688XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001689{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001690 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001691 FILE* fp = callfopen( filename, "rb" );
1692 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 }
1696 LoadFile( fp );
1697 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001699}
1700
1701
Lee Thomason2fa81722012-11-09 12:37:46 -08001702XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001703{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001704 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001705
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001706 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001707 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001708 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1709 return _errorID;
1710 }
1711
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001713 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001715 if ( filelength == -1L ) {
1716 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1717 return _errorID;
1718 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001719
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001720 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001722 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001725
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 _charBuffer = new char[size+1];
1727 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 if ( read != size ) {
1729 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001732
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001734
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 if ( !p || !*p ) {
1739 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001742
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1744 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001745}
1746
1747
Lee Thomason2fa81722012-11-09 12:37:46 -08001748XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001749{
Dmitry-Me01578db2014-08-19 10:18:48 +04001750 FILE* fp = callfopen( filename, "w" );
1751 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 SaveFile(fp, compact);
1756 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001758}
1759
1760
Lee Thomason2fa81722012-11-09 12:37:46 -08001761XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001762{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 XMLPrinter stream( fp, compact );
1764 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001766}
1767
Lee Thomason1ff38e02012-02-14 18:18:16 -08001768
Lee Thomason2fa81722012-11-09 12:37:46 -08001769XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001770{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001771 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001772 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001773
Lee Thomason82d32002014-02-21 22:47:18 -08001774 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001776 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 }
1778 if ( len == (size_t)(-1) ) {
1779 len = strlen( p );
1780 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 _charBuffer = new char[ len+1 ];
1782 memcpy( _charBuffer, p, len );
1783 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001784
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 if ( !p || !*p ) {
1788 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001791
Thomas Roß1470edc2013-05-10 15:44:12 +02001792 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001793 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001795}
1796
1797
PKEuS1c5f99e2013-07-06 11:28:39 +02001798void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001799{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 XMLPrinter stdStreamer( stdout );
1801 if ( !streamer ) {
1802 streamer = &stdStreamer;
1803 }
1804 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001805}
1806
1807
Lee Thomason2fa81722012-11-09 12:37:46 -08001808void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001809{
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 _errorID = error;
1811 _errorStr1 = str1;
1812 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001813}
1814
Lee Thomason5cae8972012-01-24 18:03:07 -08001815
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001816void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001817{
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 static const int LEN = 20;
1820 char buf1[LEN] = { 0 };
1821 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001822
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 if ( _errorStr1 ) {
1824 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 if ( _errorStr2 ) {
1827 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833}
1834
1835
PKEuS1bfb9542013-08-04 13:51:17 +02001836XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 _elementJustOpened( false ),
1838 _firstElement( true ),
1839 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001840 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 _textDepth( -1 ),
1842 _processEntities( true ),
1843 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 _entityFlag[i] = false;
1847 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 }
1849 for( int i=0; i<NUM_ENTITIES; ++i ) {
1850 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1851 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
1854 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 _restrictedEntityFlag[(int)'&'] = true;
1856 _restrictedEntityFlag[(int)'<'] = true;
1857 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1858 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001859}
1860
1861
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001862void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001863{
1864 va_list va;
1865 va_start( va, format );
1866
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 if ( _fp ) {
1868 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
1870 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001871#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001872 #if defined(WINCE)
1873 int len = 512;
1874 do {
1875 len = len*2;
1876 char* str = new char[len]();
1877 len = _vsnprintf(str, len, format, va);
1878 delete[] str;
1879 }while (len < 0);
1880 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001881 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001882 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883#else
1884 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001885#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 // Close out and re-start the va-args
1887 va_end( va );
1888 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001889 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1890#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001891 #if defined(WINCE)
1892 _vsnprintf( p, len+1, format, va );
1893 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001894 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001895 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001896#else
1897 vsnprintf( p, len+1, format, va );
1898#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001900 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001901}
1902
1903
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001904void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001905{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 for( int i=0; i<depth; ++i ) {
1907 Print( " " );
1908 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001909}
1910
1911
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001912void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 // Look for runs of bytes between entities to print.
1915 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001917
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 while ( *q ) {
1920 // Remember, char is sometimes signed. (How many times has that bitten me?)
1921 if ( *q > 0 && *q < ENTITY_RANGE ) {
1922 // Check for entities. If one is found, flush
1923 // the stream up until the entity, write the
1924 // entity, and keep looking.
1925 if ( flag[(unsigned)(*q)] ) {
1926 while ( p < q ) {
1927 Print( "%c", *p );
1928 ++p;
1929 }
1930 for( int i=0; i<NUM_ENTITIES; ++i ) {
1931 if ( entities[i].value == *q ) {
1932 Print( "&%s;", entities[i].pattern );
1933 break;
1934 }
1935 }
1936 ++p;
1937 }
1938 }
1939 ++q;
1940 }
1941 }
1942 // Flush the remaining string. This will be the entire
1943 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 Print( "%s", p );
1946 }
Lee Thomason857b8682012-01-25 17:50:25 -08001947}
1948
U-Stream\Leeae25a442012-02-17 17:48:16 -08001949
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001950void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001953 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 -07001954 Print( "%s", bom );
1955 }
1956 if ( writeDec ) {
1957 PushDeclaration( "xml version=\"1.0\"" );
1958 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001959}
1960
1961
Uli Kusterer593a33d2014-02-01 12:48:51 +01001962void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001963{
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 SealElement();
1966 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001968
Uli Kusterer593a33d2014-02-01 12:48:51 +01001969 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001971 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001972 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001973 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001975
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 _elementJustOpened = true;
1978 _firstElement = false;
1979 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001980}
1981
1982
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001983void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001984{
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 Print( " %s=\"", name );
1987 PrintString( value, false );
1988 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001989}
1990
1991
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001992void XMLPrinter::PushAttribute( const char* name, int v )
1993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 char buf[BUF_SIZE];
1995 XMLUtil::ToStr( v, buf, BUF_SIZE );
1996 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001997}
1998
1999
2000void XMLPrinter::PushAttribute( const char* name, unsigned v )
2001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 char buf[BUF_SIZE];
2003 XMLUtil::ToStr( v, buf, BUF_SIZE );
2004 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002005}
2006
2007
2008void XMLPrinter::PushAttribute( const char* name, bool v )
2009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 char buf[BUF_SIZE];
2011 XMLUtil::ToStr( v, buf, BUF_SIZE );
2012 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002013}
2014
2015
2016void XMLPrinter::PushAttribute( const char* name, double v )
2017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 char buf[BUF_SIZE];
2019 XMLUtil::ToStr( v, buf, BUF_SIZE );
2020 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002021}
2022
2023
Uli Kustererca412e82014-02-01 13:35:05 +01002024void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002025{
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 --_depth;
2027 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002028
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 Print( "/>" );
2031 }
2032 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002033 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 }
2037 Print( "</%s>", name );
2038 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002039
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 if ( _textDepth == _depth ) {
2041 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 }
Uli Kustererca412e82014-02-01 13:35:05 +01002043 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 Print( "\n" );
2045 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002047}
2048
2049
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002050void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002051{
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002054}
2055
2056
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002057void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002058{
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002060
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 SealElement();
2063 }
2064 if ( cdata ) {
2065 Print( "<![CDATA[" );
2066 Print( "%s", text );
2067 Print( "]]>" );
2068 }
2069 else {
2070 PrintString( text, true );
2071 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002072}
2073
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002074void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 char buf[BUF_SIZE];
2077 XMLUtil::ToStr( value, buf, BUF_SIZE );
2078 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002079}
2080
2081
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002082void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 char buf[BUF_SIZE];
2085 XMLUtil::ToStr( value, buf, BUF_SIZE );
2086 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002087}
2088
2089
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002090void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 char buf[BUF_SIZE];
2093 XMLUtil::ToStr( value, buf, BUF_SIZE );
2094 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002095}
2096
2097
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002098void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( value, buf, BUF_SIZE );
2102 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002103}
2104
2105
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002106void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 char buf[BUF_SIZE];
2109 XMLUtil::ToStr( value, buf, BUF_SIZE );
2110 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002111}
2112
Lee Thomason5cae8972012-01-24 18:03:07 -08002113
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002114void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002115{
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 SealElement();
2118 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002125}
Lee Thomason751da522012-02-10 08:50:51 -08002126
2127
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002128void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002129{
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 SealElement();
2132 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002139}
2140
2141
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002142void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002143{
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 SealElement();
2146 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002153}
2154
2155
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002156bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002157{
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 if ( doc.HasBOM() ) {
2160 PushHeader( true, false );
2161 }
2162 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002163}
2164
2165
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002166bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002167{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002168 const XMLElement* parentElem = element.Parent()->ToElement();
2169 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2170 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 while ( attribute ) {
2172 PushAttribute( attribute->Name(), attribute->Value() );
2173 attribute = attribute->Next();
2174 }
2175 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002176}
2177
2178
Uli Kustererca412e82014-02-01 13:35:05 +01002179bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002180{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002181 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002183}
2184
2185
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002186bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 PushText( text.Value(), text.CData() );
2189 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002190}
2191
2192
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002193bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 PushComment( comment.Value() );
2196 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002197}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002198
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002199bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 PushDeclaration( declaration.Value() );
2202 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002203}
2204
2205
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002206bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 PushUnknown( unknown.Value() );
2209 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002210}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002211
Lee Thomason685b8952012-11-12 13:00:06 -08002212} // namespace tinyxml2
2213