blob: 0e1386d729ea35cb8bf80d0f3721d8b4a9883c6b [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
73void StrPair::Reset()
74{
Lee Thomason120b3a62012-10-12 10:06:59 -070075 if ( _flags & NEEDS_DELETE ) {
76 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070077 }
Lee Thomason120b3a62012-10-12 10:06:59 -070078 _flags = 0;
79 _start = 0;
80 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081}
82
83
84void StrPair::SetStr( const char* str, int flags )
85{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070086 Reset();
87 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -070088 _start = new char[ len+1 ];
89 memcpy( _start, str, len+1 );
90 _end = _start + len;
91 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080092}
93
94
95char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
96{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070097 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080098
Dmitry-Meec19a0e2014-08-25 11:05:55 +040099 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 char endChar = *endTag;
101 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800102
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700103 // Inner loop of text parsing.
104 while ( *p ) {
105 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
106 Set( start, p, strFlags );
107 return p + length;
108 }
109 ++p;
110 }
111 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800112}
113
114
115char* StrPair::ParseName( char* p )
116{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400117 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700118 return 0;
119 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800120
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400121 char* const start = p;
122
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200123 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700124 ++p;
125 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700127 if ( p > start ) {
128 Set( start, p, 0 );
129 return p;
130 }
131 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800132}
133
134
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700135void StrPair::CollapseWhitespace()
136{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400137 // Adjusting _start would cause undefined behavior on delete[]
138 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700140 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700141
Lee Thomason120b3a62012-10-12 10:06:59 -0700142 if ( _start && *_start ) {
143 char* p = _start; // the read pointer
144 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700145
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700146 while( *p ) {
147 if ( XMLUtil::IsWhiteSpace( *p )) {
148 p = XMLUtil::SkipWhiteSpace( p );
149 if ( *p == 0 ) {
150 break; // don't write to q; this trims the trailing space.
151 }
152 *q = ' ';
153 ++q;
154 }
155 *q = *p;
156 ++q;
157 ++p;
158 }
159 *q = 0;
160 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161}
162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163
Lee Thomasone4422302012-01-20 17:59:50 -0800164const char* StrPair::GetStr()
165{
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 if ( _flags & NEEDS_FLUSH ) {
167 *_end = 0;
168 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800169
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags ) {
171 char* p = _start; // the read pointer
172 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800173
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 while( p < _end ) {
175 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700176 // CR-LF pair becomes LF
177 // CR alone becomes LF
178 // LF-CR becomes LF
179 if ( *(p+1) == LF ) {
180 p += 2;
181 }
182 else {
183 ++p;
184 }
185 *q++ = LF;
186 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700187 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700188 if ( *(p+1) == CR ) {
189 p += 2;
190 }
191 else {
192 ++p;
193 }
194 *q++ = LF;
195 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700196 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // Entities handled by tinyXML2:
198 // - special entities in the entity table [in/out]
199 // - numeric character reference [in]
200 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400203 const int buflen = 10;
204 char buf[buflen] = { 0 };
205 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400207 TIXMLASSERT( 0 <= len && len <= buflen );
208 TIXMLASSERT( q + len <= p );
209 memcpy( q, buf, len );
210 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 }
212 else {
213 int i=0;
214 for(; i<NUM_ENTITIES; ++i ) {
215 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
216 && *(p+entities[i].length+1) == ';' ) {
217 // Found an entity convert;
218 *q = entities[i].value;
219 ++q;
220 p += entities[i].length + 2;
221 break;
222 }
223 }
224 if ( i == NUM_ENTITIES ) {
225 // fixme: treat as error?
226 ++p;
227 ++q;
228 }
229 }
230 }
231 else {
232 *q = *p;
233 ++p;
234 ++q;
235 }
236 }
237 *q = 0;
238 }
239 // The loop below has plenty going on, and this
240 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 CollapseWhitespace();
243 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700244 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800247}
248
Lee Thomason2c85a712012-01-31 08:24:24 -0800249
Lee Thomasone4422302012-01-20 17:59:50 -0800250
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800251
Lee Thomason56bdd022012-02-09 18:16:58 -0800252// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800253
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800254const char* XMLUtil::ReadBOM( const char* p, bool* bom )
255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 *bom = false;
257 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
258 // Check for BOM:
259 if ( *(pu+0) == TIXML_UTF_LEAD_0
260 && *(pu+1) == TIXML_UTF_LEAD_1
261 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
262 *bom = true;
263 p += 3;
264 }
265 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266}
267
268
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800269void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 const unsigned long BYTE_MASK = 0xBF;
272 const unsigned long BYTE_MARK = 0x80;
273 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800274
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 if (input < 0x80) {
276 *length = 1;
277 }
278 else if ( input < 0x800 ) {
279 *length = 2;
280 }
281 else if ( input < 0x10000 ) {
282 *length = 3;
283 }
284 else if ( input < 0x200000 ) {
285 *length = 4;
286 }
287 else {
288 *length = 0; // This code won't covert this correctly anyway.
289 return;
290 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 // Scary scary fall throughs.
295 switch (*length) {
296 case 4:
297 --output;
298 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
299 input >>= 6;
300 case 3:
301 --output;
302 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
303 input >>= 6;
304 case 2:
305 --output;
306 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
307 input >>= 6;
308 case 1:
309 --output;
310 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100311 default:
312 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700313 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800314}
315
316
317const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 // Presume an entity, and pull it out.
320 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800321
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 if ( *(p+1) == '#' && *(p+2) ) {
323 unsigned long ucs = 0;
324 ptrdiff_t delta = 0;
325 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800326
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 if ( *(p+2) == 'x' ) {
328 // Hexadecimal.
329 if ( !*(p+3) ) {
330 return 0;
331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 const char* q = p+3;
334 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800335
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 if ( !q || !*q ) {
337 return 0;
338 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 delta = q-p;
341 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 while ( *q != 'x' ) {
344 if ( *q >= '0' && *q <= '9' ) {
345 ucs += mult * (*q - '0');
346 }
347 else if ( *q >= 'a' && *q <= 'f' ) {
348 ucs += mult * (*q - 'a' + 10);
349 }
350 else if ( *q >= 'A' && *q <= 'F' ) {
351 ucs += mult * (*q - 'A' + 10 );
352 }
353 else {
354 return 0;
355 }
356 mult *= 16;
357 --q;
358 }
359 }
360 else {
361 // Decimal.
362 if ( !*(p+2) ) {
363 return 0;
364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700366 const char* q = p+2;
367 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( !q || !*q ) {
370 return 0;
371 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800372
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 delta = q-p;
374 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700376 while ( *q != '#' ) {
377 if ( *q >= '0' && *q <= '9' ) {
378 ucs += mult * (*q - '0');
379 }
380 else {
381 return 0;
382 }
383 mult *= 10;
384 --q;
385 }
386 }
387 // convert the UCS to UTF-8
388 ConvertUTF32ToUTF8( ucs, value, length );
389 return p + delta + 1;
390 }
391 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800393
394
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700395void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700398}
399
400
401void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700404}
405
406
407void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700410}
411
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800412/*
413 ToStr() of a number is a very tricky topic.
414 https://github.com/leethomason/tinyxml2/issues/106
415*/
Lee Thomason21be8822012-07-15 17:27:22 -0700416void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
417{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800418 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
423{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800424 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428bool XMLUtil::ToInt( const char* str, int* value )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
431 return true;
432 }
433 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
439 return true;
440 }
441 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700442}
443
444bool XMLUtil::ToBool( const char* str, bool* value )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 int ival = 0;
447 if ( ToInt( str, &ival )) {
448 *value = (ival==0) ? false : true;
449 return true;
450 }
451 if ( StringEqual( str, "true" ) ) {
452 *value = true;
453 return true;
454 }
455 else if ( StringEqual( str, "false" ) ) {
456 *value = false;
457 return true;
458 }
459 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700460}
461
462
463bool XMLUtil::ToFloat( const char* str, float* value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToDouble( const char* str, double* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
474 return true;
475 }
476 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
479
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700480char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800481{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400482 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 p = XMLUtil::SkipWhiteSpace( p );
484 if( !p || !*p ) {
485 return p;
486 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800489 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 static const char* xmlHeader = { "<?" };
491 static const char* commentHeader = { "<!--" };
492 static const char* dtdHeader = { "<!" };
493 static const char* cdataHeader = { "<![CDATA[" };
494 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800495
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 static const int xmlHeaderLen = 2;
497 static const int commentHeaderLen = 4;
498 static const int dtdHeaderLen = 2;
499 static const int cdataHeaderLen = 9;
500 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800502#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800503#pragma warning ( push )
504#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800505#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800508#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800509#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800510#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400511 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700513 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
514 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 p += xmlHeaderLen;
516 }
517 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700518 returnNode = new (_commentPool.Alloc()) XMLComment( this );
519 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 p += commentHeaderLen;
521 }
522 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700523 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700525 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 p += cdataHeaderLen;
527 text->SetCData( true );
528 }
529 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700530 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
531 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p += dtdHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700535 returnNode = new (_elementPool.Alloc()) XMLElement( this );
536 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 p += elementHeaderLen;
538 }
539 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_textPool.Alloc()) XMLText( this );
541 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p = start; // Back it up, all the text counts.
543 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 *node = returnNode;
546 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800547}
548
549
Lee Thomason751da522012-02-10 08:50:51 -0800550bool XMLDocument::Accept( XMLVisitor* visitor ) const
551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 if ( visitor->VisitEnter( *this ) ) {
553 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
554 if ( !node->Accept( visitor ) ) {
555 break;
556 }
557 }
558 }
559 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800560}
Lee Thomason56bdd022012-02-09 18:16:58 -0800561
562
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563// --------- XMLNode ----------- //
564
565XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 _document( doc ),
567 _parent( 0 ),
568 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200569 _prev( 0 ), _next( 0 ),
570 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800572}
573
574
575XMLNode::~XMLNode()
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700578 if ( _parent ) {
579 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700580 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800581}
582
Michael Daumling21626882013-10-22 17:03:37 +0200583const char* XMLNode::Value() const
584{
585 return _value.GetStr();
586}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800587
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800588void XMLNode::SetValue( const char* str, bool staticMem )
589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700591 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 }
593 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800596}
597
598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800599void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600{
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 while( _firstChild ) {
602 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700604
Dmitry-Mee3225b12014-09-03 11:03:11 +0400605 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800608}
609
610
611void XMLNode::Unlink( XMLNode* child )
612{
Lee Thomason624d43f2012-10-12 10:58:48 -0700613 if ( child == _firstChild ) {
614 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 if ( child == _lastChild ) {
617 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
Lee Thomasond923c672012-01-23 08:44:25 -0800619
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 if ( child->_prev ) {
621 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 if ( child->_next ) {
624 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700626 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627}
628
629
U-Stream\Leeae25a442012-02-17 17:48:16 -0800630void XMLNode::DeleteChild( XMLNode* node )
631{
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400633 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800634}
635
636
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800637XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
638{
Michael Daumlinged523282013-10-23 07:47:29 +0200639 if (addThis->_document != _document)
640 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641
Michael Daumlinged523282013-10-23 07:47:29 +0200642 if (addThis->_parent)
643 addThis->_parent->Unlink( addThis );
644 else
645 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( _lastChild ) {
648 TIXMLASSERT( _firstChild );
649 TIXMLASSERT( _lastChild->_next == 0 );
650 _lastChild->_next = addThis;
651 addThis->_prev = _lastChild;
652 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomason624d43f2012-10-12 10:58:48 -0700654 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700655 }
656 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 TIXMLASSERT( _firstChild == 0 );
658 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_prev = 0;
661 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665}
666
667
Lee Thomason1ff38e02012-02-14 18:18:16 -0800668XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
669{
Michael Daumlinged523282013-10-23 07:47:29 +0200670 if (addThis->_document != _document)
671 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700672
Michael Daumlinged523282013-10-23 07:47:29 +0200673 if (addThis->_parent)
674 addThis->_parent->Unlink( addThis );
675 else
676 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( _firstChild ) {
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 _firstChild->_prev = addThis;
683 addThis->_next = _firstChild;
684 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
688 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_prev = 0;
693 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Michael Daumlinged523282013-10-23 07:47:29 +0200702 if (addThis->_document != _document)
703 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 return 0;
709 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 // The last node or the only node.
713 return InsertEndChild( addThis );
714 }
Michael Daumlinged523282013-10-23 07:47:29 +0200715 if (addThis->_parent)
716 addThis->_parent->Unlink( addThis );
717 else
718 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = afterThis;
720 addThis->_next = afterThis->_next;
721 afterThis->_next->_prev = addThis;
722 afterThis->_next = addThis;
723 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725}
726
727
728
729
Lee Thomason56bdd022012-02-09 18:16:58 -0800730const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800731{
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 XMLElement* element = node->ToElement();
734 if ( element ) {
735 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
736 return element;
737 }
738 }
739 }
740 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800741}
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::LastChildElement( const char* value ) const
745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800755}
756
757
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800758const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
759{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400760 for( XMLNode* node=this->_next; node; node = node->_next ) {
761 const XMLElement* element = node->ToElement();
762 if ( element
763 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
764 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
771const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
772{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400773 for( XMLNode* node=_prev; node; node = node->_prev ) {
774 const XMLElement* element = node->ToElement();
775 if ( element
776 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
777 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 // This is a recursive method, but thinking about it "at the current level"
787 // it is a pretty simple flat list:
788 // <foo/>
789 // <!-- comment -->
790 //
791 // With a special case:
792 // <foo>
793 // </foo>
794 // <!-- comment -->
795 //
796 // Where the closing element (/foo) *must* be the next thing after the opening
797 // element, and the names must match. BUT the tricky bit is that the closing
798 // element will be read by the child.
799 //
800 // 'endTag' is the end tag for this node, it is returned by a call to a child.
801 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800802
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 while( p && *p ) {
804 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800805
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 if ( p == 0 || node == 0 ) {
808 break;
809 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800810
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 StrPair endTag;
812 p = node->ParseDeep( p, &endTag );
813 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( !_document->Error() ) {
817 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 break;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400822 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400824 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 if ( parentEnd ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400826 *parentEnd = ele->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800828 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400829 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 return p;
831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // Handle an end tag returned to this level.
834 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400836 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400838 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
840 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400841 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
843 else if ( !endTag.Empty() ) {
844 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400845 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 }
847 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400848 if ( mismatch ) {
849 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
850 p = 0;
851 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 }
853 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400854 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 node = 0;
856 }
857 if ( node ) {
858 this->InsertEndChild( node );
859 }
860 }
861 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800862}
863
Dmitry-Mee3225b12014-09-03 11:03:11 +0400864void XMLNode::DeleteNode( XMLNode* node )
865{
866 if ( node == 0 ) {
867 return;
868 }
869 MemPool* pool = node->_memPool;
870 node->~XMLNode();
871 pool->Free( node );
872}
873
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800875char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 const char* start = p;
878 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 return p;
884 }
885 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
887 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 flags |= StrPair::COLLAPSE_WHITESPACE;
889 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700890
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
895 if ( p && *p ) {
896 return p-1;
897 }
898 }
899 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900}
901
902
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800903XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
909 text->SetCData( this->CData() );
910 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
914bool XMLText::ShallowEqual( const XMLNode* compare ) const
915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800917}
918
919
Lee Thomason56bdd022012-02-09 18:16:58 -0800920bool XMLText::Accept( XMLVisitor* visitor ) const
921{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800923}
924
925
Lee Thomason3f57d272012-01-11 15:30:03 -0800926// --------- XMLComment ---------- //
927
Lee Thomasone4422302012-01-20 17:59:50 -0800928XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800929{
930}
931
932
Lee Thomasonce0763e2012-01-11 15:43:54 -0800933XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800934{
Lee Thomason3f57d272012-01-11 15:30:03 -0800935}
936
937
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800938char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 // Comment parses as text.
941 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800947}
948
949
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800950XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 }
955 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
956 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957}
958
959
960bool XMLComment::ShallowEqual( const XMLNode* compare ) const
961{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400962 const XMLComment* comment = compare->ToComment();
963 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964}
965
966
Lee Thomason751da522012-02-10 08:50:51 -0800967bool XMLComment::Accept( XMLVisitor* visitor ) const
968{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800970}
Lee Thomason56bdd022012-02-09 18:16:58 -0800971
972
Lee Thomason50f97b22012-02-11 16:33:40 -0800973// --------- XMLDeclaration ---------- //
974
975XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
976{
977}
978
979
980XMLDeclaration::~XMLDeclaration()
981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800983}
984
985
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800986char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 // Declaration parses as text.
989 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800995}
996
997
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001001 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 }
1003 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1004 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
1008bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1009{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001010 const XMLDeclaration* declaration = compare->ToDeclaration();
1011 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001012}
1013
1014
1015
Lee Thomason50f97b22012-02-11 16:33:40 -08001016bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001019}
1020
1021// --------- XMLUnknown ---------- //
1022
1023XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1024{
1025}
1026
1027
1028XMLUnknown::~XMLUnknown()
1029{
1030}
1031
1032
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 // Unknown parses as text.
1036 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001037
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001043}
1044
1045
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1052 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001053}
1054
1055
1056bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1057{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001058 const XMLUnknown* unknown = compare->ToUnknown();
1059 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001060}
1061
1062
Lee Thomason50f97b22012-02-11 16:33:40 -08001063bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1064{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001066}
1067
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001068// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001069
1070const char* XMLAttribute::Name() const
1071{
1072 return _name.GetStr();
1073}
1074
1075const char* XMLAttribute::Value() const
1076{
1077 return _value.GetStr();
1078}
1079
Lee Thomason6f381b72012-03-02 12:59:39 -08001080char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 if ( !p || !*p ) {
1085 return 0;
1086 }
Lee Thomason22aead12012-01-23 13:29:35 -08001087
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 // Skip white space before =
1089 p = XMLUtil::SkipWhiteSpace( p );
1090 if ( !p || *p != '=' ) {
1091 return 0;
1092 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001093
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 ++p; // move up to opening quote
1095 p = XMLUtil::SkipWhiteSpace( p );
1096 if ( *p != '\"' && *p != '\'' ) {
1097 return 0;
1098 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001099
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 char endTag[2] = { *p, 0 };
1101 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001102
Lee Thomason624d43f2012-10-12 10:58:48 -07001103 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001105}
1106
1107
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001108void XMLAttribute::SetName( const char* n )
1109{
Lee Thomason624d43f2012-10-12 10:58:48 -07001110 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001111}
1112
1113
Lee Thomason2fa81722012-11-09 12:37:46 -08001114XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 if ( XMLUtil::ToInt( Value(), value )) {
1117 return XML_NO_ERROR;
1118 }
1119 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001120}
1121
1122
Lee Thomason2fa81722012-11-09 12:37:46 -08001123XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( XMLUtil::ToUnsigned( Value(), value )) {
1126 return XML_NO_ERROR;
1127 }
1128 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001129}
1130
1131
Lee Thomason2fa81722012-11-09 12:37:46 -08001132XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 if ( XMLUtil::ToBool( Value(), value )) {
1135 return XML_NO_ERROR;
1136 }
1137 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001138}
1139
1140
Lee Thomason2fa81722012-11-09 12:37:46 -08001141XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 if ( XMLUtil::ToFloat( Value(), value )) {
1144 return XML_NO_ERROR;
1145 }
1146 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001147}
1148
1149
Lee Thomason2fa81722012-11-09 12:37:46 -08001150XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 if ( XMLUtil::ToDouble( Value(), value )) {
1153 return XML_NO_ERROR;
1154 }
1155 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001156}
1157
1158
1159void XMLAttribute::SetAttribute( const char* v )
1160{
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162}
1163
1164
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165void XMLAttribute::SetAttribute( int v )
1166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 char buf[BUF_SIZE];
1168 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001169 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001171
1172
1173void XMLAttribute::SetAttribute( unsigned v )
1174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 char buf[BUF_SIZE];
1176 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001178}
1179
1180
1181void XMLAttribute::SetAttribute( bool v )
1182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 char buf[BUF_SIZE];
1184 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001185 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001186}
1187
1188void XMLAttribute::SetAttribute( double v )
1189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 char buf[BUF_SIZE];
1191 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001192 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001193}
1194
1195void XMLAttribute::SetAttribute( float v )
1196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 char buf[BUF_SIZE];
1198 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001200}
1201
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001202
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001203// --------- XMLElement ---------- //
1204XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001205 _closingType( 0 ),
1206 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001207{
1208}
1209
1210
1211XMLElement::~XMLElement()
1212{
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 while( _rootAttribute ) {
1214 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001215 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001216 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001218}
1219
1220
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001221XMLAttribute* XMLElement::FindAttribute( const char* name )
1222{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001223 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1225 return a;
1226 }
1227 }
1228 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231
1232const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1233{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001234 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1236 return a;
1237 }
1238 }
1239 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001243const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 const XMLAttribute* a = FindAttribute( name );
1246 if ( !a ) {
1247 return 0;
1248 }
1249 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1250 return a->Value();
1251 }
1252 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001253}
1254
1255
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001256const char* XMLElement::GetText() const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( FirstChild() && FirstChild()->ToText() ) {
1259 return FirstChild()->ToText()->Value();
1260 }
1261 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262}
1263
1264
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001265void XMLElement::SetText( const char* inText )
1266{
Uli Kusterer869bb592014-01-21 01:36:16 +01001267 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001268 FirstChild()->SetValue( inText );
1269 else {
1270 XMLText* theText = GetDocument()->NewText( inText );
1271 InsertFirstChild( theText );
1272 }
1273}
1274
Lee Thomason5bb2d802014-01-24 10:42:57 -08001275
1276void XMLElement::SetText( int v )
1277{
1278 char buf[BUF_SIZE];
1279 XMLUtil::ToStr( v, buf, BUF_SIZE );
1280 SetText( buf );
1281}
1282
1283
1284void XMLElement::SetText( unsigned v )
1285{
1286 char buf[BUF_SIZE];
1287 XMLUtil::ToStr( v, buf, BUF_SIZE );
1288 SetText( buf );
1289}
1290
1291
1292void XMLElement::SetText( bool v )
1293{
1294 char buf[BUF_SIZE];
1295 XMLUtil::ToStr( v, buf, BUF_SIZE );
1296 SetText( buf );
1297}
1298
1299
1300void XMLElement::SetText( float v )
1301{
1302 char buf[BUF_SIZE];
1303 XMLUtil::ToStr( v, buf, BUF_SIZE );
1304 SetText( buf );
1305}
1306
1307
1308void XMLElement::SetText( double v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
MortenMacFly4ee49f12013-01-14 20:03:14 +01001316XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( FirstChild() && FirstChild()->ToText() ) {
1319 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001320 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 return XML_SUCCESS;
1322 }
1323 return XML_CAN_NOT_CONVERT_TEXT;
1324 }
1325 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001326}
1327
1328
MortenMacFly4ee49f12013-01-14 20:03:14 +01001329XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( FirstChild() && FirstChild()->ToText() ) {
1332 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001333 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 return XML_SUCCESS;
1335 }
1336 return XML_CAN_NOT_CONVERT_TEXT;
1337 }
1338 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001339}
1340
1341
MortenMacFly4ee49f12013-01-14 20:03:14 +01001342XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( FirstChild() && FirstChild()->ToText() ) {
1345 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001346 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 return XML_SUCCESS;
1348 }
1349 return XML_CAN_NOT_CONVERT_TEXT;
1350 }
1351 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001352}
1353
1354
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 if ( FirstChild() && FirstChild()->ToText() ) {
1358 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001359 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 return XML_SUCCESS;
1361 }
1362 return XML_CAN_NOT_CONVERT_TEXT;
1363 }
1364 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001365}
1366
1367
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( FirstChild() && FirstChild()->ToText() ) {
1371 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001372 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 return XML_SUCCESS;
1374 }
1375 return XML_CAN_NOT_CONVERT_TEXT;
1376 }
1377 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001378}
1379
1380
1381
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001382XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 XMLAttribute* last = 0;
1385 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1390 break;
1391 }
1392 }
1393 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1395 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001397 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 }
1399 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 }
1402 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001403 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001406}
1407
1408
U-Stream\Leeae25a442012-02-17 17:48:16 -08001409void XMLElement::DeleteAttribute( const char* name )
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1414 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001420 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 break;
1422 }
1423 prev = a;
1424 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001425}
1426
1427
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001428char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 const char* start = p;
1431 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001432
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 // Read the attributes.
1434 while( p ) {
1435 p = XMLUtil::SkipWhiteSpace( p );
1436 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 return 0;
1439 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001440
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001442 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1444 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001445 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001446
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001449 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 return 0;
1452 }
1453 // There is a minor bug here: if the attribute in the source xml
1454 // document is duplicated, it will not be detected and the
1455 // attribute will be doubly added. However, tracking the 'prevAttribute'
1456 // avoids re-scanning the attribute list. Preferring performance for
1457 // now, may reconsider in the future.
1458 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 prevAttribute = attrib;
1465 }
1466 // end of the tag
1467 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 return p+2; // done; sealed element.
1470 }
1471 // end of the tag
1472 else if ( *p == '>' ) {
1473 ++p;
1474 break;
1475 }
1476 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 return 0;
1479 }
1480 }
1481 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001482}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483
Dmitry-Mee3225b12014-09-03 11:03:11 +04001484void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1485{
1486 if ( attribute == 0 ) {
1487 return;
1488 }
1489 MemPool* pool = attribute->_memPool;
1490 attribute->~XMLAttribute();
1491 pool->Free( attribute );
1492}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001493
Lee Thomason67d61312012-01-24 16:01:51 -08001494//
1495// <ele></ele>
1496// <ele>foo<b>bar</b></ele>
1497//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001498char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 // Read the element name.
1501 p = XMLUtil::SkipWhiteSpace( p );
1502 if ( !p ) {
1503 return 0;
1504 }
Lee Thomason67d61312012-01-24 16:01:51 -08001505
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 // The closing element is the </element> form. It is
1507 // parsed just like a regular element then deleted from
1508 // the DOM.
1509 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 ++p;
1512 }
Lee Thomason67d61312012-01-24 16:01:51 -08001513
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 p = _value.ParseName( p );
1515 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 return 0;
1517 }
Lee Thomason67d61312012-01-24 16:01:51 -08001518
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 return p;
1522 }
Lee Thomason67d61312012-01-24 16:01:51 -08001523
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 p = XMLNode::ParseDeep( p, strPair );
1525 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001526}
1527
1528
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001529
1530XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001533 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 }
1535 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1536 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1537 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1538 }
1539 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001540}
1541
1542
1543bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 const XMLElement* other = compare->ToElement();
1546 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 const XMLAttribute* a=FirstAttribute();
1549 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001550
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 while ( a && b ) {
1552 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1553 return false;
1554 }
1555 a = a->Next();
1556 b = b->Next();
1557 }
1558 if ( a || b ) {
1559 // different count
1560 return false;
1561 }
1562 return true;
1563 }
1564 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565}
1566
1567
Lee Thomason751da522012-02-10 08:50:51 -08001568bool XMLElement::Accept( XMLVisitor* visitor ) const
1569{
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1572 if ( !node->Accept( visitor ) ) {
1573 break;
1574 }
1575 }
1576 }
1577 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001578}
Lee Thomason56bdd022012-02-09 18:16:58 -08001579
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001580
Lee Thomason3f57d272012-01-11 15:30:03 -08001581// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001582
1583// Warning: List must match 'enum XMLError'
1584const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1585 "XML_SUCCESS",
1586 "XML_NO_ATTRIBUTE",
1587 "XML_WRONG_ATTRIBUTE_TYPE",
1588 "XML_ERROR_FILE_NOT_FOUND",
1589 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1590 "XML_ERROR_FILE_READ_ERROR",
1591 "XML_ERROR_ELEMENT_MISMATCH",
1592 "XML_ERROR_PARSING_ELEMENT",
1593 "XML_ERROR_PARSING_ATTRIBUTE",
1594 "XML_ERROR_IDENTIFYING_TAG",
1595 "XML_ERROR_PARSING_TEXT",
1596 "XML_ERROR_PARSING_CDATA",
1597 "XML_ERROR_PARSING_COMMENT",
1598 "XML_ERROR_PARSING_DECLARATION",
1599 "XML_ERROR_PARSING_UNKNOWN",
1600 "XML_ERROR_EMPTY_DOCUMENT",
1601 "XML_ERROR_MISMATCHED_ELEMENT",
1602 "XML_ERROR_PARSING",
1603 "XML_CAN_NOT_CONVERT_TEXT",
1604 "XML_NO_TEXT_NODE"
1605};
1606
1607
Lee Thomason624d43f2012-10-12 10:58:48 -07001608XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 _writeBOM( false ),
1611 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001612 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 _whitespace( whitespace ),
1614 _errorStr1( 0 ),
1615 _errorStr2( 0 ),
1616 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001617{
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001619}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001620
1621
Lee Thomason3f57d272012-01-11 15:30:03 -08001622XMLDocument::~XMLDocument()
1623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001626
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001627#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001628 _textPool.Trace( "text" );
1629 _elementPool.Trace( "element" );
1630 _commentPool.Trace( "comment" );
1631 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001632#endif
1633
Lee Thomason5b0a6772012-11-19 13:54:42 -08001634#ifdef DEBUG
1635 if ( Error() == false ) {
1636 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1637 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1638 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1639 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1640 }
1641#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001642}
1643
1644
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001645void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001646{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001647 DeleteChildren();
1648
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _errorID = XML_NO_ERROR;
1650 _errorStr1 = 0;
1651 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001652
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 delete [] _charBuffer;
1654 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001655}
1656
Lee Thomason3f57d272012-01-11 15:30:03 -08001657
Lee Thomason2c85a712012-01-31 08:24:24 -08001658XMLElement* XMLDocument::NewElement( const char* name )
1659{
Lee Thomason624d43f2012-10-12 10:58:48 -07001660 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1661 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 ele->SetName( name );
1663 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001664}
1665
1666
Lee Thomason1ff38e02012-02-14 18:18:16 -08001667XMLComment* XMLDocument::NewComment( const char* str )
1668{
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1670 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 comment->SetValue( str );
1672 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001673}
1674
1675
1676XMLText* XMLDocument::NewText( const char* str )
1677{
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1679 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 text->SetValue( str );
1681 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001682}
1683
1684
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001685XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1686{
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1688 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1690 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001691}
1692
1693
1694XMLUnknown* XMLDocument::NewUnknown( const char* str )
1695{
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1697 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 unk->SetValue( str );
1699 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001700}
1701
Dmitry-Me01578db2014-08-19 10:18:48 +04001702static FILE* callfopen( const char* filepath, const char* mode )
1703{
1704#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1705 FILE* fp = 0;
1706 errno_t err = fopen_s( &fp, filepath, mode );
1707 if ( err ) {
1708 return 0;
1709 }
1710#else
1711 FILE* fp = fopen( filepath, mode );
1712#endif
1713 return fp;
1714}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001715
Lee Thomason2fa81722012-11-09 12:37:46 -08001716XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001717{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001718 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001719 FILE* fp = callfopen( filename, "rb" );
1720 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 }
1724 LoadFile( fp );
1725 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727}
1728
1729
Lee Thomason2fa81722012-11-09 12:37:46 -08001730XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001732 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001734 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001735 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001736 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1737 return _errorID;
1738 }
1739
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001741 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001743 if ( filelength == -1L ) {
1744 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1745 return _errorID;
1746 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001747
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001748 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001750 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001753
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 _charBuffer = new char[size+1];
1755 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 if ( read != size ) {
1757 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001760
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001762
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 if ( !p || !*p ) {
1767 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001770
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1772 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001773}
1774
1775
Lee Thomason2fa81722012-11-09 12:37:46 -08001776XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001777{
Dmitry-Me01578db2014-08-19 10:18:48 +04001778 FILE* fp = callfopen( filename, "w" );
1779 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 }
1783 SaveFile(fp, compact);
1784 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001786}
1787
1788
Lee Thomason2fa81722012-11-09 12:37:46 -08001789XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001790{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 XMLPrinter stream( fp, compact );
1792 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001794}
1795
Lee Thomason1ff38e02012-02-14 18:18:16 -08001796
Lee Thomason2fa81722012-11-09 12:37:46 -08001797XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001798{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001799 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001800 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001801
Lee Thomason82d32002014-02-21 22:47:18 -08001802 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
1806 if ( len == (size_t)(-1) ) {
1807 len = strlen( p );
1808 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 _charBuffer = new char[ len+1 ];
1810 memcpy( _charBuffer, p, len );
1811 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001812
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 if ( !p || !*p ) {
1816 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001819
Thomas Roß1470edc2013-05-10 15:44:12 +02001820 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001821 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001823}
1824
1825
PKEuS1c5f99e2013-07-06 11:28:39 +02001826void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001827{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 XMLPrinter stdStreamer( stdout );
1829 if ( !streamer ) {
1830 streamer = &stdStreamer;
1831 }
1832 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001833}
1834
1835
Lee Thomason2fa81722012-11-09 12:37:46 -08001836void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001837{
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 _errorID = error;
1839 _errorStr1 = str1;
1840 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001841}
1842
Lee Thomason331596e2014-09-11 14:56:43 -07001843const char* XMLDocument::ErrorName() const
1844{
1845 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1846 return _errorNames[_errorID];
1847}
Lee Thomason5cae8972012-01-24 18:03:07 -08001848
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001849void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001850{
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 static const int LEN = 20;
1853 char buf1[LEN] = { 0 };
1854 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001855
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 if ( _errorStr1 ) {
1857 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 if ( _errorStr2 ) {
1860 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001862
Lee Thomason331596e2014-09-11 14:56:43 -07001863 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1864 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001866}
1867
1868
PKEuS1bfb9542013-08-04 13:51:17 +02001869XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 _elementJustOpened( false ),
1871 _firstElement( true ),
1872 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001873 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 _textDepth( -1 ),
1875 _processEntities( true ),
1876 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001877{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 _entityFlag[i] = false;
1880 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 }
1882 for( int i=0; i<NUM_ENTITIES; ++i ) {
1883 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1884 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 }
1887 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001888 _restrictedEntityFlag[(int)'&'] = true;
1889 _restrictedEntityFlag[(int)'<'] = true;
1890 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1891 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001892}
1893
1894
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001895void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001896{
1897 va_list va;
1898 va_start( va, format );
1899
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 if ( _fp ) {
1901 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 }
1903 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001904#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001905 #if defined(WINCE)
1906 int len = 512;
1907 do {
1908 len = len*2;
1909 char* str = new char[len]();
1910 len = _vsnprintf(str, len, format, va);
1911 delete[] str;
1912 }while (len < 0);
1913 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001914 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001915 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916#else
1917 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001918#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 // Close out and re-start the va-args
1920 va_end( va );
1921 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001922 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1923#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001924 #if defined(WINCE)
1925 _vsnprintf( p, len+1, format, va );
1926 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001927 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001928 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001929#else
1930 vsnprintf( p, len+1, format, va );
1931#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001933 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001934}
1935
1936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 for( int i=0; i<depth; ++i ) {
1940 Print( " " );
1941 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001942}
1943
1944
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001945void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 // Look for runs of bytes between entities to print.
1948 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 while ( *q ) {
1953 // Remember, char is sometimes signed. (How many times has that bitten me?)
1954 if ( *q > 0 && *q < ENTITY_RANGE ) {
1955 // Check for entities. If one is found, flush
1956 // the stream up until the entity, write the
1957 // entity, and keep looking.
1958 if ( flag[(unsigned)(*q)] ) {
1959 while ( p < q ) {
1960 Print( "%c", *p );
1961 ++p;
1962 }
1963 for( int i=0; i<NUM_ENTITIES; ++i ) {
1964 if ( entities[i].value == *q ) {
1965 Print( "&%s;", entities[i].pattern );
1966 break;
1967 }
1968 }
1969 ++p;
1970 }
1971 }
1972 ++q;
1973 }
1974 }
1975 // Flush the remaining string. This will be the entire
1976 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 Print( "%s", p );
1979 }
Lee Thomason857b8682012-01-25 17:50:25 -08001980}
1981
U-Stream\Leeae25a442012-02-17 17:48:16 -08001982
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001983void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001986 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 -07001987 Print( "%s", bom );
1988 }
1989 if ( writeDec ) {
1990 PushDeclaration( "xml version=\"1.0\"" );
1991 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001992}
1993
1994
Uli Kusterer593a33d2014-02-01 12:48:51 +01001995void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001996{
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 SealElement();
1999 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002001
Uli Kusterer593a33d2014-02-01 12:48:51 +01002002 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002004 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002005 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002008
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 _elementJustOpened = true;
2011 _firstElement = false;
2012 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002017{
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 Print( " %s=\"", name );
2020 PrintString( value, false );
2021 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002022}
2023
2024
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002025void XMLPrinter::PushAttribute( const char* name, int v )
2026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 char buf[BUF_SIZE];
2028 XMLUtil::ToStr( v, buf, BUF_SIZE );
2029 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002030}
2031
2032
2033void XMLPrinter::PushAttribute( const char* name, unsigned v )
2034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 char buf[BUF_SIZE];
2036 XMLUtil::ToStr( v, buf, BUF_SIZE );
2037 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002038}
2039
2040
2041void XMLPrinter::PushAttribute( const char* name, bool v )
2042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 char buf[BUF_SIZE];
2044 XMLUtil::ToStr( v, buf, BUF_SIZE );
2045 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002046}
2047
2048
2049void XMLPrinter::PushAttribute( const char* name, double v )
2050{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 char buf[BUF_SIZE];
2052 XMLUtil::ToStr( v, buf, BUF_SIZE );
2053 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002054}
2055
2056
Uli Kustererca412e82014-02-01 13:35:05 +01002057void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002058{
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 --_depth;
2060 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002061
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 Print( "/>" );
2064 }
2065 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002066 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 }
2070 Print( "</%s>", name );
2071 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002072
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( _textDepth == _depth ) {
2074 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
Uli Kustererca412e82014-02-01 13:35:05 +01002076 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( "\n" );
2078 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002084{
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002087}
2088
2089
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002090void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002091{
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002093
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 SealElement();
2096 }
2097 if ( cdata ) {
2098 Print( "<![CDATA[" );
2099 Print( "%s", text );
2100 Print( "]]>" );
2101 }
2102 else {
2103 PrintString( text, true );
2104 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002105}
2106
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002107void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 char buf[BUF_SIZE];
2110 XMLUtil::ToStr( value, buf, BUF_SIZE );
2111 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002112}
2113
2114
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002115void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 char buf[BUF_SIZE];
2118 XMLUtil::ToStr( value, buf, BUF_SIZE );
2119 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002120}
2121
2122
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002123void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 char buf[BUF_SIZE];
2126 XMLUtil::ToStr( value, buf, BUF_SIZE );
2127 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002128}
2129
2130
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002131void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 char buf[BUF_SIZE];
2134 XMLUtil::ToStr( value, buf, BUF_SIZE );
2135 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002136}
2137
2138
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002139void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 char buf[BUF_SIZE];
2142 XMLUtil::ToStr( value, buf, BUF_SIZE );
2143 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002144}
2145
Lee Thomason5cae8972012-01-24 18:03:07 -08002146
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002147void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002148{
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 SealElement();
2151 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002158}
Lee Thomason751da522012-02-10 08:50:51 -08002159
2160
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002161void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162{
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 SealElement();
2165 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002172}
2173
2174
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002175void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002176{
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 SealElement();
2179 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002184 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186}
2187
2188
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002189bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002190{
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 if ( doc.HasBOM() ) {
2193 PushHeader( true, false );
2194 }
2195 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002196}
2197
2198
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002199bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002200{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002201 const XMLElement* parentElem = element.Parent()->ToElement();
2202 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2203 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 while ( attribute ) {
2205 PushAttribute( attribute->Name(), attribute->Value() );
2206 attribute = attribute->Next();
2207 }
2208 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002209}
2210
2211
Uli Kustererca412e82014-02-01 13:35:05 +01002212bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002213{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002214 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002216}
2217
2218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 PushText( text.Value(), text.CData() );
2222 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002223}
2224
2225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 PushComment( comment.Value() );
2229 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002230}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002232bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 PushDeclaration( declaration.Value() );
2235 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236}
2237
2238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 PushUnknown( unknown.Value() );
2242 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002243}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002244
Lee Thomason685b8952012-11-12 13:00:06 -08002245} // namespace tinyxml2
2246