blob: 99284448bae864b6eaab9c5885cc4f6e2fee267d [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 ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400215 const Entity& entity = entities[i];
216 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
217 && *( p + entity.length + 1 ) == ';' ) {
218 // Found an entity - convert.
219 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400221 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 break;
223 }
224 }
225 if ( i == NUM_ENTITIES ) {
226 // fixme: treat as error?
227 ++p;
228 ++q;
229 }
230 }
231 }
232 else {
233 *q = *p;
234 ++p;
235 ++q;
236 }
237 }
238 *q = 0;
239 }
240 // The loop below has plenty going on, and this
241 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700242 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 CollapseWhitespace();
244 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700245 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700246 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800248}
249
Lee Thomason2c85a712012-01-31 08:24:24 -0800250
Lee Thomasone4422302012-01-20 17:59:50 -0800251
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800252
Lee Thomason56bdd022012-02-09 18:16:58 -0800253// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800254
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800255const char* XMLUtil::ReadBOM( const char* p, bool* bom )
256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700257 *bom = false;
258 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
259 // Check for BOM:
260 if ( *(pu+0) == TIXML_UTF_LEAD_0
261 && *(pu+1) == TIXML_UTF_LEAD_1
262 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
263 *bom = true;
264 p += 3;
265 }
266 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267}
268
269
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800270void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700272 const unsigned long BYTE_MASK = 0xBF;
273 const unsigned long BYTE_MARK = 0x80;
274 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800275
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700276 if (input < 0x80) {
277 *length = 1;
278 }
279 else if ( input < 0x800 ) {
280 *length = 2;
281 }
282 else if ( input < 0x10000 ) {
283 *length = 3;
284 }
285 else if ( input < 0x200000 ) {
286 *length = 4;
287 }
288 else {
289 *length = 0; // This code won't covert this correctly anyway.
290 return;
291 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800292
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800294
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 // Scary scary fall throughs.
296 switch (*length) {
297 case 4:
298 --output;
299 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
300 input >>= 6;
301 case 3:
302 --output;
303 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
304 input >>= 6;
305 case 2:
306 --output;
307 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
308 input >>= 6;
309 case 1:
310 --output;
311 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100312 default:
313 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315}
316
317
318const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700320 // Presume an entity, and pull it out.
321 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800322
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700323 if ( *(p+1) == '#' && *(p+2) ) {
324 unsigned long ucs = 0;
325 ptrdiff_t delta = 0;
326 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 if ( *(p+2) == 'x' ) {
329 // Hexadecimal.
330 if ( !*(p+3) ) {
331 return 0;
332 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800333
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 const char* q = p+3;
335 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800336
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 if ( !q || !*q ) {
338 return 0;
339 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800340
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 delta = q-p;
342 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800343
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700344 while ( *q != 'x' ) {
345 if ( *q >= '0' && *q <= '9' ) {
346 ucs += mult * (*q - '0');
347 }
348 else if ( *q >= 'a' && *q <= 'f' ) {
349 ucs += mult * (*q - 'a' + 10);
350 }
351 else if ( *q >= 'A' && *q <= 'F' ) {
352 ucs += mult * (*q - 'A' + 10 );
353 }
354 else {
355 return 0;
356 }
357 mult *= 16;
358 --q;
359 }
360 }
361 else {
362 // Decimal.
363 if ( !*(p+2) ) {
364 return 0;
365 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 const char* q = p+2;
368 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 if ( !q || !*q ) {
371 return 0;
372 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800373
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700374 delta = q-p;
375 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800376
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700377 while ( *q != '#' ) {
378 if ( *q >= '0' && *q <= '9' ) {
379 ucs += mult * (*q - '0');
380 }
381 else {
382 return 0;
383 }
384 mult *= 10;
385 --q;
386 }
387 }
388 // convert the UCS to UTF-8
389 ConvertUTF32ToUTF8( ucs, value, length );
390 return p + delta + 1;
391 }
392 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800393}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800394
395
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700396void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700399}
400
401
402void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700405}
406
407
408void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800413/*
414 ToStr() of a number is a very tricky topic.
415 https://github.com/leethomason/tinyxml2/issues/106
416*/
Lee Thomason21be8822012-07-15 17:27:22 -0700417void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
418{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800419 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700420}
421
422
423void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
424{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800425 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700426}
427
428
429bool XMLUtil::ToInt( const char* str, int* value )
430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
432 return true;
433 }
434 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700435}
436
437bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
440 return true;
441 }
442 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445bool XMLUtil::ToBool( const char* str, bool* value )
446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 int ival = 0;
448 if ( ToInt( str, &ival )) {
449 *value = (ival==0) ? false : true;
450 return true;
451 }
452 if ( StringEqual( str, "true" ) ) {
453 *value = true;
454 return true;
455 }
456 else if ( StringEqual( str, "false" ) ) {
457 *value = false;
458 return true;
459 }
460 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463
464bool XMLUtil::ToFloat( const char* str, float* value )
465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700466 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472bool XMLUtil::ToDouble( const char* str, double* value )
473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700474 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
475 return true;
476 }
477 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700478}
479
480
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700481char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800482{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400483 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 p = XMLUtil::SkipWhiteSpace( p );
485 if( !p || !*p ) {
486 return p;
487 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800488
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800490 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 static const char* xmlHeader = { "<?" };
492 static const char* commentHeader = { "<!--" };
493 static const char* dtdHeader = { "<!" };
494 static const char* cdataHeader = { "<![CDATA[" };
495 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 static const int xmlHeaderLen = 2;
498 static const int commentHeaderLen = 4;
499 static const int dtdHeaderLen = 2;
500 static const int cdataHeaderLen = 9;
501 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800503#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800504#pragma warning ( push )
505#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800506#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
508 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800509#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800510#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400512 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700514 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
515 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 p += xmlHeaderLen;
517 }
518 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700519 returnNode = new (_commentPool.Alloc()) XMLComment( this );
520 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 p += commentHeaderLen;
522 }
523 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700524 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700526 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 p += cdataHeaderLen;
528 text->SetCData( true );
529 }
530 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
532 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 p += dtdHeaderLen;
534 }
535 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700536 returnNode = new (_elementPool.Alloc()) XMLElement( this );
537 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 p += elementHeaderLen;
539 }
540 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700541 returnNode = new (_textPool.Alloc()) XMLText( this );
542 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 p = start; // Back it up, all the text counts.
544 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800545
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 *node = returnNode;
547 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800548}
549
550
Lee Thomason751da522012-02-10 08:50:51 -0800551bool XMLDocument::Accept( XMLVisitor* visitor ) const
552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 if ( visitor->VisitEnter( *this ) ) {
554 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
555 if ( !node->Accept( visitor ) ) {
556 break;
557 }
558 }
559 }
560 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800561}
Lee Thomason56bdd022012-02-09 18:16:58 -0800562
563
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800564// --------- XMLNode ----------- //
565
566XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 _document( doc ),
568 _parent( 0 ),
569 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200570 _prev( 0 ), _next( 0 ),
571 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800572{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573}
574
575
576XMLNode::~XMLNode()
577{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700578 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700579 if ( _parent ) {
580 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800582}
583
Michael Daumling21626882013-10-22 17:03:37 +0200584const char* XMLNode::Value() const
585{
586 return _value.GetStr();
587}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800588
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800589void XMLNode::SetValue( const char* str, bool staticMem )
590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700592 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 }
594 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800597}
598
599
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800600void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800601{
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 while( _firstChild ) {
603 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700605
Dmitry-Mee3225b12014-09-03 11:03:11 +0400606 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800609}
610
611
612void XMLNode::Unlink( XMLNode* child )
613{
Lee Thomason624d43f2012-10-12 10:58:48 -0700614 if ( child == _firstChild ) {
615 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 if ( child == _lastChild ) {
618 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomasond923c672012-01-23 08:44:25 -0800620
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 if ( child->_prev ) {
622 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 if ( child->_next ) {
625 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700627 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800628}
629
630
U-Stream\Leeae25a442012-02-17 17:48:16 -0800631void XMLNode::DeleteChild( XMLNode* node )
632{
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400634 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800635}
636
637
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800638XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
639{
Michael Daumlinged523282013-10-23 07:47:29 +0200640 if (addThis->_document != _document)
641 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700642
Michael Daumlinged523282013-10-23 07:47:29 +0200643 if (addThis->_parent)
644 addThis->_parent->Unlink( addThis );
645 else
646 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700647
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( _lastChild ) {
649 TIXMLASSERT( _firstChild );
650 TIXMLASSERT( _lastChild->_next == 0 );
651 _lastChild->_next = addThis;
652 addThis->_prev = _lastChild;
653 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 }
657 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 TIXMLASSERT( _firstChild == 0 );
659 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800660
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 addThis->_prev = 0;
662 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700664 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800666}
667
668
Lee Thomason1ff38e02012-02-14 18:18:16 -0800669XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
670{
Michael Daumlinged523282013-10-23 07:47:29 +0200671 if (addThis->_document != _document)
672 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700673
Michael Daumlinged523282013-10-23 07:47:29 +0200674 if (addThis->_parent)
675 addThis->_parent->Unlink( addThis );
676 else
677 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700678
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 if ( _firstChild ) {
680 TIXMLASSERT( _lastChild );
681 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 _firstChild->_prev = addThis;
684 addThis->_next = _firstChild;
685 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
689 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( _lastChild == 0 );
691 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_prev = 0;
694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400697 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800698}
699
700
701XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
702{
Michael Daumlinged523282013-10-23 07:47:29 +0200703 if (addThis->_document != _document)
704 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700707
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 return 0;
710 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800711
Lee Thomason624d43f2012-10-12 10:58:48 -0700712 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700713 // The last node or the only node.
714 return InsertEndChild( addThis );
715 }
Michael Daumlinged523282013-10-23 07:47:29 +0200716 if (addThis->_parent)
717 addThis->_parent->Unlink( addThis );
718 else
719 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 addThis->_prev = afterThis;
721 addThis->_next = afterThis->_next;
722 afterThis->_next->_prev = addThis;
723 afterThis->_next = addThis;
724 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800726}
727
728
729
730
Lee Thomason56bdd022012-02-09 18:16:58 -0800731const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800732{
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 XMLElement* element = node->ToElement();
735 if ( element ) {
736 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
737 return element;
738 }
739 }
740 }
741 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800742}
743
744
Lee Thomason56bdd022012-02-09 18:16:58 -0800745const XMLElement* XMLNode::LastChildElement( const char* value ) const
746{
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 XMLElement* element = node->ToElement();
749 if ( element ) {
750 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
751 return element;
752 }
753 }
754 }
755 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800756}
757
758
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800759const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
760{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400761 for( XMLNode* node=this->_next; node; node = node->_next ) {
762 const XMLElement* element = node->ToElement();
763 if ( element
764 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
765 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
767 }
768 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800769}
770
771
772const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
773{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400774 for( XMLNode* node=_prev; node; node = node->_prev ) {
775 const XMLElement* element = node->ToElement();
776 if ( element
777 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
778 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 }
780 }
781 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782}
783
784
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800785char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800786{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 // This is a recursive method, but thinking about it "at the current level"
788 // it is a pretty simple flat list:
789 // <foo/>
790 // <!-- comment -->
791 //
792 // With a special case:
793 // <foo>
794 // </foo>
795 // <!-- comment -->
796 //
797 // Where the closing element (/foo) *must* be the next thing after the opening
798 // element, and the names must match. BUT the tricky bit is that the closing
799 // element will be read by the child.
800 //
801 // 'endTag' is the end tag for this node, it is returned by a call to a child.
802 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800803
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 while( p && *p ) {
805 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800806
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 if ( p == 0 || node == 0 ) {
809 break;
810 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800811
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 StrPair endTag;
813 p = node->ParseDeep( p, &endTag );
814 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400815 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 if ( !_document->Error() ) {
818 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
820 break;
821 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800822
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400823 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400825 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 if ( parentEnd ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400827 *parentEnd = ele->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800829 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400830 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return p;
832 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 // Handle an end tag returned to this level.
835 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400837 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400839 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
841 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400842 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
844 else if ( !endTag.Empty() ) {
845 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400846 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 }
848 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400849 if ( mismatch ) {
850 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
851 p = 0;
852 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400855 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 node = 0;
857 }
858 if ( node ) {
859 this->InsertEndChild( node );
860 }
861 }
862 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800863}
864
Dmitry-Mee3225b12014-09-03 11:03:11 +0400865void XMLNode::DeleteNode( XMLNode* node )
866{
867 if ( node == 0 ) {
868 return;
869 }
870 MemPool* pool = node->_memPool;
871 node->~XMLNode();
872 pool->Free( node );
873}
874
Lee Thomason5492a1c2012-01-23 15:32:10 -0800875// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800876char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800877{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 const char* start = p;
879 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 return p;
885 }
886 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
888 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 flags |= StrPair::COLLAPSE_WHITESPACE;
890 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700891
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 if ( p && *p ) {
897 return p-1;
898 }
899 }
900 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800901}
902
903
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800904XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
905{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700907 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 }
909 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
910 text->SetCData( this->CData() );
911 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800912}
913
914
915bool XMLText::ShallowEqual( const XMLNode* compare ) const
916{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400917 const XMLText* text = compare->ToText();
918 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800919}
920
921
Lee Thomason56bdd022012-02-09 18:16:58 -0800922bool XMLText::Accept( XMLVisitor* visitor ) const
923{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800925}
926
927
Lee Thomason3f57d272012-01-11 15:30:03 -0800928// --------- XMLComment ---------- //
929
Lee Thomasone4422302012-01-20 17:59:50 -0800930XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800931{
932}
933
934
Lee Thomasonce0763e2012-01-11 15:43:54 -0800935XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800936{
Lee Thomason3f57d272012-01-11 15:30:03 -0800937}
938
939
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800940char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 // Comment parses as text.
943 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 }
948 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800949}
950
951
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
958 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959}
960
961
962bool XMLComment::ShallowEqual( const XMLNode* compare ) const
963{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400964 const XMLComment* comment = compare->ToComment();
965 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800966}
967
968
Lee Thomason751da522012-02-10 08:50:51 -0800969bool XMLComment::Accept( XMLVisitor* visitor ) const
970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800972}
Lee Thomason56bdd022012-02-09 18:16:58 -0800973
974
Lee Thomason50f97b22012-02-11 16:33:40 -0800975// --------- XMLDeclaration ---------- //
976
977XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
978{
979}
980
981
982XMLDeclaration::~XMLDeclaration()
983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800985}
986
987
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800988char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 // Declaration parses as text.
991 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
996 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800997}
998
999
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001000XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001003 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 }
1005 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1006 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001007}
1008
1009
1010bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1011{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001012 const XMLDeclaration* declaration = compare->ToDeclaration();
1013 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001014}
1015
1016
1017
Lee Thomason50f97b22012-02-11 16:33:40 -08001018bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001021}
1022
1023// --------- XMLUnknown ---------- //
1024
1025XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1026{
1027}
1028
1029
1030XMLUnknown::~XMLUnknown()
1031{
1032}
1033
1034
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001035char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 // Unknown parses as text.
1038 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001039
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001045}
1046
1047
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001048XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001051 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
1053 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1054 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001055}
1056
1057
1058bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1059{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001060 const XMLUnknown* unknown = compare->ToUnknown();
1061 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001062}
1063
1064
Lee Thomason50f97b22012-02-11 16:33:40 -08001065bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1066{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001070// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001071
1072const char* XMLAttribute::Name() const
1073{
1074 return _name.GetStr();
1075}
1076
1077const char* XMLAttribute::Value() const
1078{
1079 return _value.GetStr();
1080}
1081
Lee Thomason6f381b72012-03-02 12:59:39 -08001082char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( !p || !*p ) {
1087 return 0;
1088 }
Lee Thomason22aead12012-01-23 13:29:35 -08001089
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 // Skip white space before =
1091 p = XMLUtil::SkipWhiteSpace( p );
1092 if ( !p || *p != '=' ) {
1093 return 0;
1094 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001095
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 ++p; // move up to opening quote
1097 p = XMLUtil::SkipWhiteSpace( p );
1098 if ( *p != '\"' && *p != '\'' ) {
1099 return 0;
1100 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001101
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 char endTag[2] = { *p, 0 };
1103 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001104
Lee Thomason624d43f2012-10-12 10:58:48 -07001105 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001107}
1108
1109
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001110void XMLAttribute::SetName( const char* n )
1111{
Lee Thomason624d43f2012-10-12 10:58:48 -07001112 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001113}
1114
1115
Lee Thomason2fa81722012-11-09 12:37:46 -08001116XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 if ( XMLUtil::ToInt( Value(), value )) {
1119 return XML_NO_ERROR;
1120 }
1121 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122}
1123
1124
Lee Thomason2fa81722012-11-09 12:37:46 -08001125XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 if ( XMLUtil::ToUnsigned( Value(), value )) {
1128 return XML_NO_ERROR;
1129 }
1130 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131}
1132
1133
Lee Thomason2fa81722012-11-09 12:37:46 -08001134XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( XMLUtil::ToBool( Value(), value )) {
1137 return XML_NO_ERROR;
1138 }
1139 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140}
1141
1142
Lee Thomason2fa81722012-11-09 12:37:46 -08001143XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 if ( XMLUtil::ToFloat( Value(), value )) {
1146 return XML_NO_ERROR;
1147 }
1148 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001149}
1150
1151
Lee Thomason2fa81722012-11-09 12:37:46 -08001152XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001153{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 if ( XMLUtil::ToDouble( Value(), value )) {
1155 return XML_NO_ERROR;
1156 }
1157 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158}
1159
1160
1161void XMLAttribute::SetAttribute( const char* v )
1162{
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001164}
1165
1166
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167void XMLAttribute::SetAttribute( int v )
1168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 char buf[BUF_SIZE];
1170 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001171 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001173
1174
1175void XMLAttribute::SetAttribute( unsigned v )
1176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 char buf[BUF_SIZE];
1178 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001180}
1181
1182
1183void XMLAttribute::SetAttribute( bool v )
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 char buf[BUF_SIZE];
1186 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001188}
1189
1190void XMLAttribute::SetAttribute( double v )
1191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 char buf[BUF_SIZE];
1193 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001194 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001195}
1196
1197void XMLAttribute::SetAttribute( float v )
1198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 char buf[BUF_SIZE];
1200 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001202}
1203
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001204
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205// --------- XMLElement ---------- //
1206XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001207 _closingType( 0 ),
1208 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001209{
1210}
1211
1212
1213XMLElement::~XMLElement()
1214{
Lee Thomason624d43f2012-10-12 10:58:48 -07001215 while( _rootAttribute ) {
1216 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001217 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001218 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001220}
1221
1222
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223XMLAttribute* XMLElement::FindAttribute( const char* name )
1224{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001225 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1227 return a;
1228 }
1229 }
1230 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001231}
1232
1233
1234const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1235{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001236 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1238 return a;
1239 }
1240 }
1241 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001242}
1243
1244
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001245const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 const XMLAttribute* a = FindAttribute( name );
1248 if ( !a ) {
1249 return 0;
1250 }
1251 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1252 return a->Value();
1253 }
1254 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001255}
1256
1257
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001258const char* XMLElement::GetText() const
1259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001261 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 }
1263 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001264}
1265
1266
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001267void XMLElement::SetText( const char* inText )
1268{
Uli Kusterer869bb592014-01-21 01:36:16 +01001269 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001270 FirstChild()->SetValue( inText );
1271 else {
1272 XMLText* theText = GetDocument()->NewText( inText );
1273 InsertFirstChild( theText );
1274 }
1275}
1276
Lee Thomason5bb2d802014-01-24 10:42:57 -08001277
1278void XMLElement::SetText( int v )
1279{
1280 char buf[BUF_SIZE];
1281 XMLUtil::ToStr( v, buf, BUF_SIZE );
1282 SetText( buf );
1283}
1284
1285
1286void XMLElement::SetText( unsigned v )
1287{
1288 char buf[BUF_SIZE];
1289 XMLUtil::ToStr( v, buf, BUF_SIZE );
1290 SetText( buf );
1291}
1292
1293
1294void XMLElement::SetText( bool v )
1295{
1296 char buf[BUF_SIZE];
1297 XMLUtil::ToStr( v, buf, BUF_SIZE );
1298 SetText( buf );
1299}
1300
1301
1302void XMLElement::SetText( float v )
1303{
1304 char buf[BUF_SIZE];
1305 XMLUtil::ToStr( v, buf, BUF_SIZE );
1306 SetText( buf );
1307}
1308
1309
1310void XMLElement::SetText( double v )
1311{
1312 char buf[BUF_SIZE];
1313 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314 SetText( buf );
1315}
1316
1317
MortenMacFly4ee49f12013-01-14 20:03:14 +01001318XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001321 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001322 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 return XML_SUCCESS;
1324 }
1325 return XML_CAN_NOT_CONVERT_TEXT;
1326 }
1327 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001328}
1329
1330
MortenMacFly4ee49f12013-01-14 20:03:14 +01001331XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001334 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001335 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 return XML_SUCCESS;
1337 }
1338 return XML_CAN_NOT_CONVERT_TEXT;
1339 }
1340 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001341}
1342
1343
MortenMacFly4ee49f12013-01-14 20:03:14 +01001344XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001347 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 return XML_SUCCESS;
1350 }
1351 return XML_CAN_NOT_CONVERT_TEXT;
1352 }
1353 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001354}
1355
1356
MortenMacFly4ee49f12013-01-14 20:03:14 +01001357XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001360 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 return XML_SUCCESS;
1363 }
1364 return XML_CAN_NOT_CONVERT_TEXT;
1365 }
1366 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001367}
1368
1369
MortenMacFly4ee49f12013-01-14 20:03:14 +01001370XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001373 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 return XML_SUCCESS;
1376 }
1377 return XML_CAN_NOT_CONVERT_TEXT;
1378 }
1379 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001380}
1381
1382
1383
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001384XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1385{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 XMLAttribute* last = 0;
1387 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001390 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1392 break;
1393 }
1394 }
1395 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1397 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 }
1401 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001402 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001405 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 }
1407 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001408}
1409
1410
U-Stream\Leeae25a442012-02-17 17:48:16 -08001411void XMLElement::DeleteAttribute( const char* name )
1412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1416 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001422 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 break;
1424 }
1425 prev = a;
1426 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001427}
1428
1429
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001430char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 const char* start = p;
1433 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001434
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 // Read the attributes.
1436 while( p ) {
1437 p = XMLUtil::SkipWhiteSpace( p );
1438 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 return 0;
1441 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001442
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001444 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1446 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001447 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001448
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001451 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 return 0;
1454 }
1455 // There is a minor bug here: if the attribute in the source xml
1456 // document is duplicated, it will not be detected and the
1457 // attribute will be doubly added. However, tracking the 'prevAttribute'
1458 // avoids re-scanning the attribute list. Preferring performance for
1459 // now, may reconsider in the future.
1460 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 }
1463 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 }
1466 prevAttribute = attrib;
1467 }
1468 // end of the tag
1469 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 return p+2; // done; sealed element.
1472 }
1473 // end of the tag
1474 else if ( *p == '>' ) {
1475 ++p;
1476 break;
1477 }
1478 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 return 0;
1481 }
1482 }
1483 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001484}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001485
Dmitry-Mee3225b12014-09-03 11:03:11 +04001486void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1487{
1488 if ( attribute == 0 ) {
1489 return;
1490 }
1491 MemPool* pool = attribute->_memPool;
1492 attribute->~XMLAttribute();
1493 pool->Free( attribute );
1494}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001495
Lee Thomason67d61312012-01-24 16:01:51 -08001496//
1497// <ele></ele>
1498// <ele>foo<b>bar</b></ele>
1499//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001500char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 // Read the element name.
1503 p = XMLUtil::SkipWhiteSpace( p );
1504 if ( !p ) {
1505 return 0;
1506 }
Lee Thomason67d61312012-01-24 16:01:51 -08001507
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 // The closing element is the </element> form. It is
1509 // parsed just like a regular element then deleted from
1510 // the DOM.
1511 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 ++p;
1514 }
Lee Thomason67d61312012-01-24 16:01:51 -08001515
Lee Thomason624d43f2012-10-12 10:58:48 -07001516 p = _value.ParseName( p );
1517 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 return 0;
1519 }
Lee Thomason67d61312012-01-24 16:01:51 -08001520
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 return p;
1524 }
Lee Thomason67d61312012-01-24 16:01:51 -08001525
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 p = XMLNode::ParseDeep( p, strPair );
1527 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001528}
1529
1530
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001531
1532XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1538 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1539 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1540 }
1541 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001542}
1543
1544
1545bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 const XMLElement* other = compare->ToElement();
1548 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001549
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 const XMLAttribute* a=FirstAttribute();
1551 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001552
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 while ( a && b ) {
1554 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1555 return false;
1556 }
1557 a = a->Next();
1558 b = b->Next();
1559 }
1560 if ( a || b ) {
1561 // different count
1562 return false;
1563 }
1564 return true;
1565 }
1566 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001567}
1568
1569
Lee Thomason751da522012-02-10 08:50:51 -08001570bool XMLElement::Accept( XMLVisitor* visitor ) const
1571{
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1574 if ( !node->Accept( visitor ) ) {
1575 break;
1576 }
1577 }
1578 }
1579 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001580}
Lee Thomason56bdd022012-02-09 18:16:58 -08001581
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomason3f57d272012-01-11 15:30:03 -08001583// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001584
1585// Warning: List must match 'enum XMLError'
1586const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1587 "XML_SUCCESS",
1588 "XML_NO_ATTRIBUTE",
1589 "XML_WRONG_ATTRIBUTE_TYPE",
1590 "XML_ERROR_FILE_NOT_FOUND",
1591 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1592 "XML_ERROR_FILE_READ_ERROR",
1593 "XML_ERROR_ELEMENT_MISMATCH",
1594 "XML_ERROR_PARSING_ELEMENT",
1595 "XML_ERROR_PARSING_ATTRIBUTE",
1596 "XML_ERROR_IDENTIFYING_TAG",
1597 "XML_ERROR_PARSING_TEXT",
1598 "XML_ERROR_PARSING_CDATA",
1599 "XML_ERROR_PARSING_COMMENT",
1600 "XML_ERROR_PARSING_DECLARATION",
1601 "XML_ERROR_PARSING_UNKNOWN",
1602 "XML_ERROR_EMPTY_DOCUMENT",
1603 "XML_ERROR_MISMATCHED_ELEMENT",
1604 "XML_ERROR_PARSING",
1605 "XML_CAN_NOT_CONVERT_TEXT",
1606 "XML_NO_TEXT_NODE"
1607};
1608
1609
Lee Thomason624d43f2012-10-12 10:58:48 -07001610XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 _writeBOM( false ),
1613 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001614 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 _whitespace( whitespace ),
1616 _errorStr1( 0 ),
1617 _errorStr2( 0 ),
1618 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001619{
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001621}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001622
1623
Lee Thomason3f57d272012-01-11 15:30:03 -08001624XMLDocument::~XMLDocument()
1625{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001626 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001627}
1628
1629
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001630void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001631{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001632 DeleteChildren();
1633
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 _errorID = XML_NO_ERROR;
1635 _errorStr1 = 0;
1636 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001637
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 delete [] _charBuffer;
1639 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001640
1641#if 0
1642 _textPool.Trace( "text" );
1643 _elementPool.Trace( "element" );
1644 _commentPool.Trace( "comment" );
1645 _attributePool.Trace( "attribute" );
1646#endif
1647
1648#ifdef DEBUG
1649 if ( Error() == false ) {
1650 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1651 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1652 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1653 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1654 }
1655#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001656}
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658
Lee Thomason2c85a712012-01-31 08:24:24 -08001659XMLElement* XMLDocument::NewElement( const char* name )
1660{
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1662 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 ele->SetName( name );
1664 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001665}
1666
1667
Lee Thomason1ff38e02012-02-14 18:18:16 -08001668XMLComment* XMLDocument::NewComment( const char* str )
1669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1671 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 comment->SetValue( str );
1673 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001674}
1675
1676
1677XMLText* XMLDocument::NewText( const char* str )
1678{
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1680 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 text->SetValue( str );
1682 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001683}
1684
1685
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001686XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1687{
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1689 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1691 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001692}
1693
1694
1695XMLUnknown* XMLDocument::NewUnknown( const char* str )
1696{
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1698 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 unk->SetValue( str );
1700 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001701}
1702
Dmitry-Me01578db2014-08-19 10:18:48 +04001703static FILE* callfopen( const char* filepath, const char* mode )
1704{
1705#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1706 FILE* fp = 0;
1707 errno_t err = fopen_s( &fp, filepath, mode );
1708 if ( err ) {
1709 return 0;
1710 }
1711#else
1712 FILE* fp = fopen( filepath, mode );
1713#endif
1714 return fp;
1715}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001716
Lee Thomason2fa81722012-11-09 12:37:46 -08001717XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001718{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001719 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001720 FILE* fp = callfopen( filename, "rb" );
1721 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
1725 LoadFile( fp );
1726 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728}
1729
1730
Lee Thomason2fa81722012-11-09 12:37:46 -08001731XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001732{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001733 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001734
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001735 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001736 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001737 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1738 return _errorID;
1739 }
1740
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001742 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001744 if ( filelength == -1L ) {
1745 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1746 return _errorID;
1747 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001748
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001749 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001751 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001754
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 _charBuffer = new char[size+1];
1756 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 if ( read != size ) {
1758 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001761
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001763
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 if ( !p || !*p ) {
1768 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001771
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1773 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001774}
1775
1776
Lee Thomason2fa81722012-11-09 12:37:46 -08001777XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001778{
Dmitry-Me01578db2014-08-19 10:18:48 +04001779 FILE* fp = callfopen( filename, "w" );
1780 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
1784 SaveFile(fp, compact);
1785 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001787}
1788
1789
Lee Thomason2fa81722012-11-09 12:37:46 -08001790XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001791{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 XMLPrinter stream( fp, compact );
1793 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001795}
1796
Lee Thomason1ff38e02012-02-14 18:18:16 -08001797
Lee Thomason2fa81722012-11-09 12:37:46 -08001798XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001799{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001800 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001801 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001802
Lee Thomason82d32002014-02-21 22:47:18 -08001803 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
1807 if ( len == (size_t)(-1) ) {
1808 len = strlen( p );
1809 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 _charBuffer = new char[ len+1 ];
1811 memcpy( _charBuffer, p, len );
1812 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001813
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 if ( !p || !*p ) {
1817 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001820
Thomas Roß1470edc2013-05-10 15:44:12 +02001821 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001822 ParseDeep( _charBuffer+delta, 0 );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001823 if (_errorID) {
1824 // clean up now essentially dangling memory.
1825 // and the parse fail can put objects in the
1826 // pools that are dead and inaccessible.
1827 DeleteChildren();
1828 _elementPool.Clear();
1829 _attributePool.Clear();
1830 _textPool.Clear();
1831 _commentPool.Clear();
1832 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001834}
1835
1836
PKEuS1c5f99e2013-07-06 11:28:39 +02001837void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 XMLPrinter stdStreamer( stdout );
1840 if ( !streamer ) {
1841 streamer = &stdStreamer;
1842 }
1843 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001844}
1845
1846
Lee Thomason2fa81722012-11-09 12:37:46 -08001847void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001848{
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _errorID = error;
1850 _errorStr1 = str1;
1851 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001852}
1853
Lee Thomason331596e2014-09-11 14:56:43 -07001854const char* XMLDocument::ErrorName() const
1855{
1856 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1857 return _errorNames[_errorID];
1858}
Lee Thomason5cae8972012-01-24 18:03:07 -08001859
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001860void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001861{
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 static const int LEN = 20;
1864 char buf1[LEN] = { 0 };
1865 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001866
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 if ( _errorStr1 ) {
1868 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 if ( _errorStr2 ) {
1871 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001873
Lee Thomason331596e2014-09-11 14:56:43 -07001874 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1875 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001877}
1878
1879
PKEuS1bfb9542013-08-04 13:51:17 +02001880XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 _elementJustOpened( false ),
1882 _firstElement( true ),
1883 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001884 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 _textDepth( -1 ),
1886 _processEntities( true ),
1887 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001888{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 _entityFlag[i] = false;
1891 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
1893 for( int i=0; i<NUM_ENTITIES; ++i ) {
1894 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1895 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 }
1898 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 _restrictedEntityFlag[(int)'&'] = true;
1900 _restrictedEntityFlag[(int)'<'] = true;
1901 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1902 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001903}
1904
1905
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001906void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001907{
1908 va_list va;
1909 va_start( va, format );
1910
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 if ( _fp ) {
1912 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 }
1914 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001915#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001916 #if defined(WINCE)
1917 int len = 512;
1918 do {
1919 len = len*2;
1920 char* str = new char[len]();
1921 len = _vsnprintf(str, len, format, va);
1922 delete[] str;
1923 }while (len < 0);
1924 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001925 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001926 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927#else
1928 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001929#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 // Close out and re-start the va-args
1931 va_end( va );
1932 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001933 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1934#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001935 #if defined(WINCE)
1936 _vsnprintf( p, len+1, format, va );
1937 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001938 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001939 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001940#else
1941 vsnprintf( p, len+1, format, va );
1942#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001944 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001945}
1946
1947
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001948void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001949{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 for( int i=0; i<depth; ++i ) {
1951 Print( " " );
1952 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001953}
1954
1955
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001956void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001957{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 // Look for runs of bytes between entities to print.
1959 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001961
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 while ( *q ) {
1964 // Remember, char is sometimes signed. (How many times has that bitten me?)
1965 if ( *q > 0 && *q < ENTITY_RANGE ) {
1966 // Check for entities. If one is found, flush
1967 // the stream up until the entity, write the
1968 // entity, and keep looking.
1969 if ( flag[(unsigned)(*q)] ) {
1970 while ( p < q ) {
1971 Print( "%c", *p );
1972 ++p;
1973 }
1974 for( int i=0; i<NUM_ENTITIES; ++i ) {
1975 if ( entities[i].value == *q ) {
1976 Print( "&%s;", entities[i].pattern );
1977 break;
1978 }
1979 }
1980 ++p;
1981 }
1982 }
1983 ++q;
1984 }
1985 }
1986 // Flush the remaining string. This will be the entire
1987 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 Print( "%s", p );
1990 }
Lee Thomason857b8682012-01-25 17:50:25 -08001991}
1992
U-Stream\Leeae25a442012-02-17 17:48:16 -08001993
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001994void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001997 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 -07001998 Print( "%s", bom );
1999 }
2000 if ( writeDec ) {
2001 PushDeclaration( "xml version=\"1.0\"" );
2002 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002003}
2004
2005
Uli Kusterer593a33d2014-02-01 12:48:51 +01002006void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002007{
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 SealElement();
2010 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002012
Uli Kusterer593a33d2014-02-01 12:48:51 +01002013 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002015 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002016 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002019
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 _elementJustOpened = true;
2022 _firstElement = false;
2023 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002024}
2025
2026
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002027void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002028{
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 Print( " %s=\"", name );
2031 PrintString( value, false );
2032 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002033}
2034
2035
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002036void XMLPrinter::PushAttribute( const char* name, int v )
2037{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 char buf[BUF_SIZE];
2039 XMLUtil::ToStr( v, buf, BUF_SIZE );
2040 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002041}
2042
2043
2044void XMLPrinter::PushAttribute( const char* name, unsigned v )
2045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 char buf[BUF_SIZE];
2047 XMLUtil::ToStr( v, buf, BUF_SIZE );
2048 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002049}
2050
2051
2052void XMLPrinter::PushAttribute( const char* name, bool v )
2053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 char buf[BUF_SIZE];
2055 XMLUtil::ToStr( v, buf, BUF_SIZE );
2056 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002057}
2058
2059
2060void XMLPrinter::PushAttribute( const char* name, double v )
2061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 char buf[BUF_SIZE];
2063 XMLUtil::ToStr( v, buf, BUF_SIZE );
2064 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002065}
2066
2067
Uli Kustererca412e82014-02-01 13:35:05 +01002068void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002069{
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 --_depth;
2071 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002072
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 Print( "/>" );
2075 }
2076 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002077 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 }
2081 Print( "</%s>", name );
2082 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002083
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 if ( _textDepth == _depth ) {
2085 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 }
Uli Kustererca412e82014-02-01 13:35:05 +01002087 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 Print( "\n" );
2089 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002091}
2092
2093
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002094void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002095{
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002098}
2099
2100
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002101void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002102{
Lee Thomason624d43f2012-10-12 10:58:48 -07002103 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002104
Lee Thomason624d43f2012-10-12 10:58:48 -07002105 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 SealElement();
2107 }
2108 if ( cdata ) {
2109 Print( "<![CDATA[" );
2110 Print( "%s", text );
2111 Print( "]]>" );
2112 }
2113 else {
2114 PrintString( text, true );
2115 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002116}
2117
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002118void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 char buf[BUF_SIZE];
2121 XMLUtil::ToStr( value, buf, BUF_SIZE );
2122 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002123}
2124
2125
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002126void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 char buf[BUF_SIZE];
2129 XMLUtil::ToStr( value, buf, BUF_SIZE );
2130 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002131}
2132
2133
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002134void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 char buf[BUF_SIZE];
2137 XMLUtil::ToStr( value, buf, BUF_SIZE );
2138 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002139}
2140
2141
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002142void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 char buf[BUF_SIZE];
2145 XMLUtil::ToStr( value, buf, BUF_SIZE );
2146 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002147}
2148
2149
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002150void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 char buf[BUF_SIZE];
2153 XMLUtil::ToStr( value, buf, BUF_SIZE );
2154 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002155}
2156
Lee Thomason5cae8972012-01-24 18:03:07 -08002157
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002158void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002159{
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 SealElement();
2162 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002167 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002169}
Lee Thomason751da522012-02-10 08:50:51 -08002170
2171
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002172void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002173{
Lee Thomason624d43f2012-10-12 10:58:48 -07002174 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 SealElement();
2176 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002183}
2184
2185
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002186void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187{
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 SealElement();
2190 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002197}
2198
2199
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002200bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002201{
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 if ( doc.HasBOM() ) {
2204 PushHeader( true, false );
2205 }
2206 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002207}
2208
2209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002211{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002212 const XMLElement* parentElem = element.Parent()->ToElement();
2213 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2214 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 while ( attribute ) {
2216 PushAttribute( attribute->Name(), attribute->Value() );
2217 attribute = attribute->Next();
2218 }
2219 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002220}
2221
2222
Uli Kustererca412e82014-02-01 13:35:05 +01002223bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002224{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002225 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002227}
2228
2229
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002230bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 PushText( text.Value(), text.CData() );
2233 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 PushComment( comment.Value() );
2240 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002241}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002243bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 PushDeclaration( declaration.Value() );
2246 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002247}
2248
2249
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002250bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002251{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 PushUnknown( unknown.Value() );
2253 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002255
Lee Thomason685b8952012-11-12 13:00:06 -08002256} // namespace tinyxml2
2257