blob: 2893a2798e53295d7619e9000cbb6a889414cf88 [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 Thomasona9cf3f92012-10-11 16:56:51 -07001626 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001627 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001628
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001629#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001630 _textPool.Trace( "text" );
1631 _elementPool.Trace( "element" );
1632 _commentPool.Trace( "comment" );
1633 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001634#endif
1635
Lee Thomason5b0a6772012-11-19 13:54:42 -08001636#ifdef DEBUG
1637 if ( Error() == false ) {
1638 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1639 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1640 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1641 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1642 }
1643#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001644}
1645
1646
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001647void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001648{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001649 DeleteChildren();
1650
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _errorID = XML_NO_ERROR;
1652 _errorStr1 = 0;
1653 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001654
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 delete [] _charBuffer;
1656 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001657}
1658
Lee Thomason3f57d272012-01-11 15:30:03 -08001659
Lee Thomason2c85a712012-01-31 08:24:24 -08001660XMLElement* XMLDocument::NewElement( const char* name )
1661{
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1663 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 ele->SetName( name );
1665 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001666}
1667
1668
Lee Thomason1ff38e02012-02-14 18:18:16 -08001669XMLComment* XMLDocument::NewComment( const char* str )
1670{
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1672 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 comment->SetValue( str );
1674 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001675}
1676
1677
1678XMLText* XMLDocument::NewText( const char* str )
1679{
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1681 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 text->SetValue( str );
1683 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001684}
1685
1686
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001687XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1688{
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1690 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1692 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001693}
1694
1695
1696XMLUnknown* XMLDocument::NewUnknown( const char* str )
1697{
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1699 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 unk->SetValue( str );
1701 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001702}
1703
Dmitry-Me01578db2014-08-19 10:18:48 +04001704static FILE* callfopen( const char* filepath, const char* mode )
1705{
1706#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1707 FILE* fp = 0;
1708 errno_t err = fopen_s( &fp, filepath, mode );
1709 if ( err ) {
1710 return 0;
1711 }
1712#else
1713 FILE* fp = fopen( filepath, mode );
1714#endif
1715 return fp;
1716}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001717
Lee Thomason2fa81722012-11-09 12:37:46 -08001718XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001719{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001720 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001721 FILE* fp = callfopen( filename, "rb" );
1722 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 }
1726 LoadFile( fp );
1727 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001729}
1730
1731
Lee Thomason2fa81722012-11-09 12:37:46 -08001732XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001734 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001735
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001736 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001737 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001738 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1739 return _errorID;
1740 }
1741
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001743 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001745 if ( filelength == -1L ) {
1746 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1747 return _errorID;
1748 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001749
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001750 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001752 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001755
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 _charBuffer = new char[size+1];
1757 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 if ( read != size ) {
1759 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001760 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001762
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001764
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 if ( !p || !*p ) {
1769 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001772
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1774 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001775}
1776
1777
Lee Thomason2fa81722012-11-09 12:37:46 -08001778XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001779{
Dmitry-Me01578db2014-08-19 10:18:48 +04001780 FILE* fp = callfopen( filename, "w" );
1781 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 }
1785 SaveFile(fp, compact);
1786 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001788}
1789
1790
Lee Thomason2fa81722012-11-09 12:37:46 -08001791XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001792{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 XMLPrinter stream( fp, compact );
1794 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796}
1797
Lee Thomason1ff38e02012-02-14 18:18:16 -08001798
Lee Thomason2fa81722012-11-09 12:37:46 -08001799XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001800{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001801 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001802 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001803
Lee Thomason82d32002014-02-21 22:47:18 -08001804 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 }
1808 if ( len == (size_t)(-1) ) {
1809 len = strlen( p );
1810 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 _charBuffer = new char[ len+1 ];
1812 memcpy( _charBuffer, p, len );
1813 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001814
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 if ( !p || !*p ) {
1818 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001821
Thomas Roß1470edc2013-05-10 15:44:12 +02001822 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001823 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001825}
1826
1827
PKEuS1c5f99e2013-07-06 11:28:39 +02001828void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 XMLPrinter stdStreamer( stdout );
1831 if ( !streamer ) {
1832 streamer = &stdStreamer;
1833 }
1834 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001835}
1836
1837
Lee Thomason2fa81722012-11-09 12:37:46 -08001838void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001839{
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _errorID = error;
1841 _errorStr1 = str1;
1842 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001843}
1844
Lee Thomason331596e2014-09-11 14:56:43 -07001845const char* XMLDocument::ErrorName() const
1846{
1847 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1848 return _errorNames[_errorID];
1849}
Lee Thomason5cae8972012-01-24 18:03:07 -08001850
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001851void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001852{
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 static const int LEN = 20;
1855 char buf1[LEN] = { 0 };
1856 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001857
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 if ( _errorStr1 ) {
1859 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 if ( _errorStr2 ) {
1862 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001864
Lee Thomason331596e2014-09-11 14:56:43 -07001865 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1866 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001868}
1869
1870
PKEuS1bfb9542013-08-04 13:51:17 +02001871XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _elementJustOpened( false ),
1873 _firstElement( true ),
1874 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001875 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 _textDepth( -1 ),
1877 _processEntities( true ),
1878 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001879{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 _entityFlag[i] = false;
1882 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 for( int i=0; i<NUM_ENTITIES; ++i ) {
1885 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1886 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 }
1889 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 _restrictedEntityFlag[(int)'&'] = true;
1891 _restrictedEntityFlag[(int)'<'] = true;
1892 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1893 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001894}
1895
1896
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001897void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001898{
1899 va_list va;
1900 va_start( va, format );
1901
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 if ( _fp ) {
1903 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 }
1905 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001906#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001907 #if defined(WINCE)
1908 int len = 512;
1909 do {
1910 len = len*2;
1911 char* str = new char[len]();
1912 len = _vsnprintf(str, len, format, va);
1913 delete[] str;
1914 }while (len < 0);
1915 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001916 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001917 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918#else
1919 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001920#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 // Close out and re-start the va-args
1922 va_end( va );
1923 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001924 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1925#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001926 #if defined(WINCE)
1927 _vsnprintf( p, len+1, format, va );
1928 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001929 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001930 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001931#else
1932 vsnprintf( p, len+1, format, va );
1933#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001935 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001936}
1937
1938
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001939void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 for( int i=0; i<depth; ++i ) {
1942 Print( " " );
1943 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001944}
1945
1946
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001947void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 // Look for runs of bytes between entities to print.
1950 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001952
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 while ( *q ) {
1955 // Remember, char is sometimes signed. (How many times has that bitten me?)
1956 if ( *q > 0 && *q < ENTITY_RANGE ) {
1957 // Check for entities. If one is found, flush
1958 // the stream up until the entity, write the
1959 // entity, and keep looking.
1960 if ( flag[(unsigned)(*q)] ) {
1961 while ( p < q ) {
1962 Print( "%c", *p );
1963 ++p;
1964 }
1965 for( int i=0; i<NUM_ENTITIES; ++i ) {
1966 if ( entities[i].value == *q ) {
1967 Print( "&%s;", entities[i].pattern );
1968 break;
1969 }
1970 }
1971 ++p;
1972 }
1973 }
1974 ++q;
1975 }
1976 }
1977 // Flush the remaining string. This will be the entire
1978 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 Print( "%s", p );
1981 }
Lee Thomason857b8682012-01-25 17:50:25 -08001982}
1983
U-Stream\Leeae25a442012-02-17 17:48:16 -08001984
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001985void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001988 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 -07001989 Print( "%s", bom );
1990 }
1991 if ( writeDec ) {
1992 PushDeclaration( "xml version=\"1.0\"" );
1993 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001994}
1995
1996
Uli Kusterer593a33d2014-02-01 12:48:51 +01001997void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001998{
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 SealElement();
2001 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002002 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002003
Uli Kusterer593a33d2014-02-01 12:48:51 +01002004 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002006 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002007 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002010
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002012 _elementJustOpened = true;
2013 _firstElement = false;
2014 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002015}
2016
2017
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002018void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002019{
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 Print( " %s=\"", name );
2022 PrintString( value, false );
2023 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002024}
2025
2026
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002027void XMLPrinter::PushAttribute( const char* name, int v )
2028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 char buf[BUF_SIZE];
2030 XMLUtil::ToStr( v, buf, BUF_SIZE );
2031 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002032}
2033
2034
2035void XMLPrinter::PushAttribute( const char* name, unsigned v )
2036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 char buf[BUF_SIZE];
2038 XMLUtil::ToStr( v, buf, BUF_SIZE );
2039 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002040}
2041
2042
2043void XMLPrinter::PushAttribute( const char* name, bool v )
2044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 char buf[BUF_SIZE];
2046 XMLUtil::ToStr( v, buf, BUF_SIZE );
2047 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002048}
2049
2050
2051void XMLPrinter::PushAttribute( const char* name, double v )
2052{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 char buf[BUF_SIZE];
2054 XMLUtil::ToStr( v, buf, BUF_SIZE );
2055 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002056}
2057
2058
Uli Kustererca412e82014-02-01 13:35:05 +01002059void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002060{
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 --_depth;
2062 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002063
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 Print( "/>" );
2066 }
2067 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002068 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 }
2072 Print( "</%s>", name );
2073 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002074
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 if ( _textDepth == _depth ) {
2076 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
Uli Kustererca412e82014-02-01 13:35:05 +01002078 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 Print( "\n" );
2080 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002082}
2083
2084
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002085void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002086{
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002089}
2090
2091
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002092void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002093{
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002095
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 SealElement();
2098 }
2099 if ( cdata ) {
2100 Print( "<![CDATA[" );
2101 Print( "%s", text );
2102 Print( "]]>" );
2103 }
2104 else {
2105 PrintString( text, true );
2106 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002107}
2108
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002109void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 char buf[BUF_SIZE];
2112 XMLUtil::ToStr( value, buf, BUF_SIZE );
2113 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002114}
2115
2116
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002117void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( value, buf, BUF_SIZE );
2121 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002122}
2123
2124
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002125void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 char buf[BUF_SIZE];
2128 XMLUtil::ToStr( value, buf, BUF_SIZE );
2129 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002130}
2131
2132
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002133void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 char buf[BUF_SIZE];
2136 XMLUtil::ToStr( value, buf, BUF_SIZE );
2137 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002138}
2139
2140
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002141void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 char buf[BUF_SIZE];
2144 XMLUtil::ToStr( value, buf, BUF_SIZE );
2145 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002146}
2147
Lee Thomason5cae8972012-01-24 18:03:07 -08002148
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002149void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002150{
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 SealElement();
2153 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002160}
Lee Thomason751da522012-02-10 08:50:51 -08002161
2162
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002163void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002164{
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 SealElement();
2167 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002174}
2175
2176
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002177void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002178{
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 SealElement();
2181 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002184 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188}
2189
2190
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002191bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002192{
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 if ( doc.HasBOM() ) {
2195 PushHeader( true, false );
2196 }
2197 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002198}
2199
2200
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002201bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002202{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002203 const XMLElement* parentElem = element.Parent()->ToElement();
2204 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2205 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 while ( attribute ) {
2207 PushAttribute( attribute->Name(), attribute->Value() );
2208 attribute = attribute->Next();
2209 }
2210 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002211}
2212
2213
Uli Kustererca412e82014-02-01 13:35:05 +01002214bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002215{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002216 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002218}
2219
2220
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002221bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 PushText( text.Value(), text.CData() );
2224 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002225}
2226
2227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 PushComment( comment.Value() );
2231 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002232}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002233
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002234bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 PushDeclaration( declaration.Value() );
2237 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238}
2239
2240
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002241bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 PushUnknown( unknown.Value() );
2244 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002245}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002246
Lee Thomason685b8952012-11-12 13:00:06 -08002247} // namespace tinyxml2
2248