blob: 91f4011d54b28f7ac47812264f0431b40c262b84 [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
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
414void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700417}
418
419
420void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800425/*
426 ToStr() of a number is a very tricky topic.
427 https://github.com/leethomason/tinyxml2/issues/106
428*/
Lee Thomason21be8822012-07-15 17:27:22 -0700429void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
430{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800431 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700432}
433
434
435void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
436{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800437 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441bool XMLUtil::ToInt( const char* str, int* value )
442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
444 return true;
445 }
446 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
449bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
452 return true;
453 }
454 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457bool XMLUtil::ToBool( const char* str, bool* value )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 int ival = 0;
460 if ( ToInt( str, &ival )) {
461 *value = (ival==0) ? false : true;
462 return true;
463 }
464 if ( StringEqual( str, "true" ) ) {
465 *value = true;
466 return true;
467 }
468 else if ( StringEqual( str, "false" ) ) {
469 *value = false;
470 return true;
471 }
472 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700473}
474
475
476bool XMLUtil::ToFloat( const char* str, float* value )
477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
479 return true;
480 }
481 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484bool XMLUtil::ToDouble( const char* str, double* value )
485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700493char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 XMLNode* returnNode = 0;
496 char* start = p;
497 p = XMLUtil::SkipWhiteSpace( p );
498 if( !p || !*p ) {
499 return p;
500 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800503 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 static const char* xmlHeader = { "<?" };
505 static const char* commentHeader = { "<!--" };
506 static const char* dtdHeader = { "<!" };
507 static const char* cdataHeader = { "<![CDATA[" };
508 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800509
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 static const int xmlHeaderLen = 2;
511 static const int commentHeaderLen = 4;
512 static const int dtdHeaderLen = 2;
513 static const int cdataHeaderLen = 9;
514 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800515
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800516#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800517#pragma warning ( push )
518#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800519#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
521 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800522#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800523#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700526 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
527 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 p += xmlHeaderLen;
529 }
530 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 returnNode = new (_commentPool.Alloc()) XMLComment( this );
532 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 p += commentHeaderLen;
534 }
535 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700536 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += cdataHeaderLen;
540 text->SetCData( true );
541 }
542 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += dtdHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_elementPool.Alloc()) XMLElement( this );
549 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += elementHeaderLen;
551 }
552 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 returnNode = new (_textPool.Alloc()) XMLText( this );
554 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p = start; // Back it up, all the text counts.
556 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800557
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 *node = returnNode;
559 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800560}
561
562
Lee Thomason751da522012-02-10 08:50:51 -0800563bool XMLDocument::Accept( XMLVisitor* visitor ) const
564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 if ( visitor->VisitEnter( *this ) ) {
566 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
567 if ( !node->Accept( visitor ) ) {
568 break;
569 }
570 }
571 }
572 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800573}
Lee Thomason56bdd022012-02-09 18:16:58 -0800574
575
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576// --------- XMLNode ----------- //
577
578XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700579 _document( doc ),
580 _parent( 0 ),
581 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200582 _prev( 0 ), _next( 0 ),
Uli Kustererd5c9e8b2014-02-01 12:48:51 +0100583 _memPool( 0 ),
584 _forceCompactMode( false )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800585{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586}
587
588
589XMLNode::~XMLNode()
590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700592 if ( _parent ) {
593 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800595}
596
Michael Daumling21626882013-10-22 17:03:37 +0200597const char* XMLNode::Value() const
598{
599 return _value.GetStr();
600}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800601
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800602void XMLNode::SetValue( const char* str, bool staticMem )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700605 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
607 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800610}
611
612
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800613void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614{
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 while( _firstChild ) {
616 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700618
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 DELETE_NODE( node );
620 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800622}
623
624
625void XMLNode::Unlink( XMLNode* child )
626{
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 if ( child == _firstChild ) {
628 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 if ( child == _lastChild ) {
631 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 }
Lee Thomasond923c672012-01-23 08:44:25 -0800633
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 if ( child->_prev ) {
635 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child->_next ) {
638 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700640 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641}
642
643
U-Stream\Leeae25a442012-02-17 17:48:16 -0800644void XMLNode::DeleteChild( XMLNode* node )
645{
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800648}
649
650
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652{
Michael Daumlinged523282013-10-23 07:47:29 +0200653 if (addThis->_document != _document)
654 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700655
Michael Daumlinged523282013-10-23 07:47:29 +0200656 if (addThis->_parent)
657 addThis->_parent->Unlink( addThis );
658 else
659 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700660
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 if ( _lastChild ) {
662 TIXMLASSERT( _firstChild );
663 TIXMLASSERT( _lastChild->_next == 0 );
664 _lastChild->_next = addThis;
665 addThis->_prev = _lastChild;
666 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 }
670 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 TIXMLASSERT( _firstChild == 0 );
672 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 addThis->_prev = 0;
675 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800679}
680
681
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
683{
Michael Daumlinged523282013-10-23 07:47:29 +0200684 if (addThis->_document != _document)
685 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700686
Michael Daumlinged523282013-10-23 07:47:29 +0200687 if (addThis->_parent)
688 addThis->_parent->Unlink( addThis );
689 else
690 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 if ( _firstChild ) {
693 TIXMLASSERT( _lastChild );
694 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 _firstChild->_prev = addThis;
697 addThis->_next = _firstChild;
698 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800699
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 }
702 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 TIXMLASSERT( _lastChild == 0 );
704 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 addThis->_prev = 0;
707 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200710 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800711}
712
713
714XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
715{
Michael Daumlinged523282013-10-23 07:47:29 +0200716 if (addThis->_document != _document)
717 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 return 0;
723 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 // The last node or the only node.
727 return InsertEndChild( addThis );
728 }
Michael Daumlinged523282013-10-23 07:47:29 +0200729 if (addThis->_parent)
730 addThis->_parent->Unlink( addThis );
731 else
732 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 addThis->_prev = afterThis;
734 addThis->_next = afterThis->_next;
735 afterThis->_next->_prev = addThis;
736 afterThis->_next = addThis;
737 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800739}
740
741
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800755}
756
757
Lee Thomason56bdd022012-02-09 18:16:58 -0800758const XMLElement* XMLNode::LastChildElement( const char* value ) const
759{
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 XMLElement* element = node->ToElement();
762 if ( element ) {
763 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
764 return element;
765 }
766 }
767 }
768 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800769}
770
771
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
773{
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 if ( element->ToElement()
776 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
777 return element->ToElement();
778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
784const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
785{
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 if ( element->ToElement()
788 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
789 return element->ToElement();
790 }
791 }
792 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800793}
794
795
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800796char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800797{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 // This is a recursive method, but thinking about it "at the current level"
799 // it is a pretty simple flat list:
800 // <foo/>
801 // <!-- comment -->
802 //
803 // With a special case:
804 // <foo>
805 // </foo>
806 // <!-- comment -->
807 //
808 // Where the closing element (/foo) *must* be the next thing after the opening
809 // element, and the names must match. BUT the tricky bit is that the closing
810 // element will be read by the child.
811 //
812 // 'endTag' is the end tag for this node, it is returned by a call to a child.
813 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800814
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 while( p && *p ) {
816 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800817
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 if ( p == 0 || node == 0 ) {
820 break;
821 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800822
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 StrPair endTag;
824 p = node->ParseDeep( p, &endTag );
825 if ( !p ) {
826 DELETE_NODE( node );
827 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 if ( !_document->Error() ) {
829 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 }
831 break;
832 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 // We read the end tag. Return it to the parent.
835 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
836 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800839 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 DELETE_NODE( node );
841 return p;
842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 // Handle an end tag returned to this level.
845 // And handle a bunch of annoying errors.
846 XMLElement* ele = node->ToElement();
847 if ( ele ) {
848 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 p = 0;
851 }
852 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 p = 0;
855 }
856 else if ( !endTag.Empty() ) {
857 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 p = 0;
860 }
861 }
862 }
863 if ( p == 0 ) {
864 DELETE_NODE( node );
865 node = 0;
866 }
867 if ( node ) {
868 this->InsertEndChild( node );
869 }
870 }
871 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800872}
873
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800875char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 const char* start = p;
878 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 return p;
884 }
885 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
887 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 flags |= StrPair::COLLAPSE_WHITESPACE;
889 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700890
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
895 if ( p && *p ) {
896 return p-1;
897 }
898 }
899 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900}
901
902
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800903XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
909 text->SetCData( this->CData() );
910 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
914bool XMLText::ShallowEqual( const XMLNode* compare ) const
915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800917}
918
919
Lee Thomason56bdd022012-02-09 18:16:58 -0800920bool XMLText::Accept( XMLVisitor* visitor ) const
921{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800923}
924
925
Lee Thomason3f57d272012-01-11 15:30:03 -0800926// --------- XMLComment ---------- //
927
Lee Thomasone4422302012-01-20 17:59:50 -0800928XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800929{
930}
931
932
Lee Thomasonce0763e2012-01-11 15:43:54 -0800933XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800934{
Lee Thomason3f57d272012-01-11 15:30:03 -0800935}
936
937
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800938char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 // Comment parses as text.
941 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800947}
948
949
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800950XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 }
955 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
956 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957}
958
959
960bool XMLComment::ShallowEqual( const XMLNode* compare ) const
961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963}
964
965
Lee Thomason751da522012-02-10 08:50:51 -0800966bool XMLComment::Accept( XMLVisitor* visitor ) const
967{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800969}
Lee Thomason56bdd022012-02-09 18:16:58 -0800970
971
Lee Thomason50f97b22012-02-11 16:33:40 -0800972// --------- XMLDeclaration ---------- //
973
974XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
975{
976}
977
978
979XMLDeclaration::~XMLDeclaration()
980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800982}
983
984
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800985char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 // Declaration parses as text.
988 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
993 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800994}
995
996
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800997XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
998{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001000 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 }
1002 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1003 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
1007bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019// --------- XMLUnknown ---------- //
1020
1021XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLUnknown::~XMLUnknown()
1027{
1028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Unknown parses as text.
1034 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1050 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
Lee Thomason50f97b22012-02-11 16:33:40 -08001060bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001065// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001066
1067const char* XMLAttribute::Name() const
1068{
1069 return _name.GetStr();
1070}
1071
1072const char* XMLAttribute::Value() const
1073{
1074 return _value.GetStr();
1075}
1076
Lee Thomason6f381b72012-03-02 12:59:39 -08001077char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001080 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 if ( !p || !*p ) {
1082 return 0;
1083 }
Lee Thomason22aead12012-01-23 13:29:35 -08001084
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 // Skip white space before =
1086 p = XMLUtil::SkipWhiteSpace( p );
1087 if ( !p || *p != '=' ) {
1088 return 0;
1089 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001090
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 ++p; // move up to opening quote
1092 p = XMLUtil::SkipWhiteSpace( p );
1093 if ( *p != '\"' && *p != '\'' ) {
1094 return 0;
1095 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001096
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 char endTag[2] = { *p, 0 };
1098 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001099
Lee Thomason624d43f2012-10-12 10:58:48 -07001100 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001102}
1103
1104
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001105void XMLAttribute::SetName( const char* n )
1106{
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001108}
1109
1110
Lee Thomason2fa81722012-11-09 12:37:46 -08001111XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( XMLUtil::ToInt( Value(), value )) {
1114 return XML_NO_ERROR;
1115 }
1116 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117}
1118
1119
Lee Thomason2fa81722012-11-09 12:37:46 -08001120XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 if ( XMLUtil::ToUnsigned( Value(), value )) {
1123 return XML_NO_ERROR;
1124 }
1125 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126}
1127
1128
Lee Thomason2fa81722012-11-09 12:37:46 -08001129XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 if ( XMLUtil::ToBool( Value(), value )) {
1132 return XML_NO_ERROR;
1133 }
1134 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135}
1136
1137
Lee Thomason2fa81722012-11-09 12:37:46 -08001138XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 if ( XMLUtil::ToFloat( Value(), value )) {
1141 return XML_NO_ERROR;
1142 }
1143 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001144}
1145
1146
Lee Thomason2fa81722012-11-09 12:37:46 -08001147XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( XMLUtil::ToDouble( Value(), value )) {
1150 return XML_NO_ERROR;
1151 }
1152 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001153}
1154
1155
1156void XMLAttribute::SetAttribute( const char* v )
1157{
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001159}
1160
1161
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162void XMLAttribute::SetAttribute( int v )
1163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 char buf[BUF_SIZE];
1165 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001168
1169
1170void XMLAttribute::SetAttribute( unsigned v )
1171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 char buf[BUF_SIZE];
1173 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001174 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001175}
1176
1177
1178void XMLAttribute::SetAttribute( bool v )
1179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 char buf[BUF_SIZE];
1181 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001182 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001183}
1184
1185void XMLAttribute::SetAttribute( double v )
1186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 char buf[BUF_SIZE];
1188 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001190}
1191
1192void XMLAttribute::SetAttribute( float v )
1193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 char buf[BUF_SIZE];
1195 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001197}
1198
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001199
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001200// --------- XMLElement ---------- //
1201XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 _closingType( 0 ),
1203 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001204{
1205}
1206
1207
1208XMLElement::~XMLElement()
1209{
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 while( _rootAttribute ) {
1211 XMLAttribute* next = _rootAttribute->_next;
1212 DELETE_ATTRIBUTE( _rootAttribute );
1213 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001215}
1216
1217
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218XMLAttribute* XMLElement::FindAttribute( const char* name )
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001221 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1223 return a;
1224 }
1225 }
1226 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227}
1228
1229
1230const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1235 return a;
1236 }
1237 }
1238 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239}
1240
1241
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001242const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 const XMLAttribute* a = FindAttribute( name );
1245 if ( !a ) {
1246 return 0;
1247 }
1248 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1249 return a->Value();
1250 }
1251 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001252}
1253
1254
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001255const char* XMLElement::GetText() const
1256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 if ( FirstChild() && FirstChild()->ToText() ) {
1258 return FirstChild()->ToText()->Value();
1259 }
1260 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001261}
1262
1263
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001264void XMLElement::SetText( const char* inText )
1265{
Uli Kusterer869bb592014-01-21 01:36:16 +01001266 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001267 FirstChild()->SetValue( inText );
1268 else {
1269 XMLText* theText = GetDocument()->NewText( inText );
1270 InsertFirstChild( theText );
1271 }
1272}
1273
Lee Thomason5bb2d802014-01-24 10:42:57 -08001274
1275void XMLElement::SetText( int v )
1276{
1277 char buf[BUF_SIZE];
1278 XMLUtil::ToStr( v, buf, BUF_SIZE );
1279 SetText( buf );
1280}
1281
1282
1283void XMLElement::SetText( unsigned v )
1284{
1285 char buf[BUF_SIZE];
1286 XMLUtil::ToStr( v, buf, BUF_SIZE );
1287 SetText( buf );
1288}
1289
1290
1291void XMLElement::SetText( bool v )
1292{
1293 char buf[BUF_SIZE];
1294 XMLUtil::ToStr( v, buf, BUF_SIZE );
1295 SetText( buf );
1296}
1297
1298
1299void XMLElement::SetText( float v )
1300{
1301 char buf[BUF_SIZE];
1302 XMLUtil::ToStr( v, buf, BUF_SIZE );
1303 SetText( buf );
1304}
1305
1306
1307void XMLElement::SetText( double v )
1308{
1309 char buf[BUF_SIZE];
1310 XMLUtil::ToStr( v, buf, BUF_SIZE );
1311 SetText( buf );
1312}
1313
1314
MortenMacFly4ee49f12013-01-14 20:03:14 +01001315XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001316{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 if ( FirstChild() && FirstChild()->ToText() ) {
1318 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001319 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 return XML_SUCCESS;
1321 }
1322 return XML_CAN_NOT_CONVERT_TEXT;
1323 }
1324 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001325}
1326
1327
MortenMacFly4ee49f12013-01-14 20:03:14 +01001328XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001329{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 if ( FirstChild() && FirstChild()->ToText() ) {
1331 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001332 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 return XML_SUCCESS;
1334 }
1335 return XML_CAN_NOT_CONVERT_TEXT;
1336 }
1337 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001338}
1339
1340
MortenMacFly4ee49f12013-01-14 20:03:14 +01001341XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( FirstChild() && FirstChild()->ToText() ) {
1344 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001345 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 return XML_SUCCESS;
1347 }
1348 return XML_CAN_NOT_CONVERT_TEXT;
1349 }
1350 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001351}
1352
1353
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 if ( FirstChild() && FirstChild()->ToText() ) {
1357 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001358 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 return XML_SUCCESS;
1360 }
1361 return XML_CAN_NOT_CONVERT_TEXT;
1362 }
1363 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001364}
1365
1366
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 if ( FirstChild() && FirstChild()->ToText() ) {
1370 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001371 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 return XML_SUCCESS;
1373 }
1374 return XML_CAN_NOT_CONVERT_TEXT;
1375 }
1376 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001377}
1378
1379
1380
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001381XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 XMLAttribute* last = 0;
1384 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001387 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1389 break;
1390 }
1391 }
1392 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001393 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1394 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 }
1398 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 }
1401 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001402 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 }
1404 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001405}
1406
1407
U-Stream\Leeae25a442012-02-17 17:48:16 -08001408void XMLElement::DeleteAttribute( const char* name )
1409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001411 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1413 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 }
1416 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 }
1419 DELETE_ATTRIBUTE( a );
1420 break;
1421 }
1422 prev = a;
1423 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001424}
1425
1426
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001427char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 const char* start = p;
1430 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001431
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 // Read the attributes.
1433 while( p ) {
1434 p = XMLUtil::SkipWhiteSpace( p );
1435 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 return 0;
1438 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001439
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001441 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1443 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001444 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001445
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( !p || Attribute( attrib->Name() ) ) {
1448 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 return 0;
1451 }
1452 // There is a minor bug here: if the attribute in the source xml
1453 // document is duplicated, it will not be detected and the
1454 // attribute will be doubly added. However, tracking the 'prevAttribute'
1455 // avoids re-scanning the attribute list. Preferring performance for
1456 // now, may reconsider in the future.
1457 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001458 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 }
1460 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 }
1463 prevAttribute = attrib;
1464 }
1465 // end of the tag
1466 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001467 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 return p+2; // done; sealed element.
1469 }
1470 // end of the tag
1471 else if ( *p == '>' ) {
1472 ++p;
1473 break;
1474 }
1475 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 return 0;
1478 }
1479 }
1480 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001481}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001482
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483
Lee Thomason67d61312012-01-24 16:01:51 -08001484//
1485// <ele></ele>
1486// <ele>foo<b>bar</b></ele>
1487//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001488char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001489{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 // Read the element name.
1491 p = XMLUtil::SkipWhiteSpace( p );
1492 if ( !p ) {
1493 return 0;
1494 }
Lee Thomason67d61312012-01-24 16:01:51 -08001495
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 // The closing element is the </element> form. It is
1497 // parsed just like a regular element then deleted from
1498 // the DOM.
1499 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 ++p;
1502 }
Lee Thomason67d61312012-01-24 16:01:51 -08001503
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 p = _value.ParseName( p );
1505 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 return 0;
1507 }
Lee Thomason67d61312012-01-24 16:01:51 -08001508
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return p;
1512 }
Lee Thomason67d61312012-01-24 16:01:51 -08001513
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 p = XMLNode::ParseDeep( p, strPair );
1515 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001516}
1517
1518
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001519
1520XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 }
1525 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1526 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1527 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1528 }
1529 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001530}
1531
1532
1533bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 const XMLElement* other = compare->ToElement();
1536 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001537
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 const XMLAttribute* a=FirstAttribute();
1539 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001540
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 while ( a && b ) {
1542 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1543 return false;
1544 }
1545 a = a->Next();
1546 b = b->Next();
1547 }
1548 if ( a || b ) {
1549 // different count
1550 return false;
1551 }
1552 return true;
1553 }
1554 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001555}
1556
1557
Lee Thomason751da522012-02-10 08:50:51 -08001558bool XMLElement::Accept( XMLVisitor* visitor ) const
1559{
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1562 if ( !node->Accept( visitor ) ) {
1563 break;
1564 }
1565 }
1566 }
1567 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001568}
Lee Thomason56bdd022012-02-09 18:16:58 -08001569
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001570
Lee Thomason3f57d272012-01-11 15:30:03 -08001571// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001572XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 _writeBOM( false ),
1575 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001576 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 _whitespace( whitespace ),
1578 _errorStr1( 0 ),
1579 _errorStr2( 0 ),
1580 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001581{
Lee Thomason624d43f2012-10-12 10:58:48 -07001582 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001583}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001584
1585
Lee Thomason3f57d272012-01-11 15:30:03 -08001586XMLDocument::~XMLDocument()
1587{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001589 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001590
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001591#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001592 _textPool.Trace( "text" );
1593 _elementPool.Trace( "element" );
1594 _commentPool.Trace( "comment" );
1595 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001596#endif
1597
Lee Thomason5b0a6772012-11-19 13:54:42 -08001598#ifdef DEBUG
1599 if ( Error() == false ) {
1600 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1601 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1602 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1603 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1604 }
1605#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001606}
1607
1608
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001609void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001610{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001611 DeleteChildren();
1612
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 _errorID = XML_NO_ERROR;
1614 _errorStr1 = 0;
1615 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001616
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 delete [] _charBuffer;
1618 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001619}
1620
Lee Thomason3f57d272012-01-11 15:30:03 -08001621
Lee Thomason2c85a712012-01-31 08:24:24 -08001622XMLElement* XMLDocument::NewElement( const char* name )
1623{
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1625 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 ele->SetName( name );
1627 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001628}
1629
1630
Lee Thomason1ff38e02012-02-14 18:18:16 -08001631XMLComment* XMLDocument::NewComment( const char* str )
1632{
Lee Thomason624d43f2012-10-12 10:58:48 -07001633 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1634 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 comment->SetValue( str );
1636 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001637}
1638
1639
1640XMLText* XMLDocument::NewText( const char* str )
1641{
Lee Thomason624d43f2012-10-12 10:58:48 -07001642 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1643 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 text->SetValue( str );
1645 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001646}
1647
1648
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001649XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1650{
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1652 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1654 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001655}
1656
1657
1658XMLUnknown* XMLDocument::NewUnknown( const char* str )
1659{
Lee Thomason624d43f2012-10-12 10:58:48 -07001660 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1661 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 unk->SetValue( str );
1663 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001664}
1665
1666
Lee Thomason2fa81722012-11-09 12:37:46 -08001667XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001668{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001669 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001671
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1673 errno_t err = fopen_s(&fp, filename, "rb" );
1674 if ( !fp || err) {
1675#else
1676 fp = fopen( filename, "rb" );
1677 if ( !fp) {
1678#endif
1679 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 }
1682 LoadFile( fp );
1683 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001685}
1686
1687
Lee Thomason2fa81722012-11-09 12:37:46 -08001688XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001689{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001690 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001691
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001692 fseek( fp, 0, SEEK_SET );
1693 fgetc( fp );
1694 if ( ferror( fp ) != 0 ) {
1695 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1696 return _errorID;
1697 }
1698
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 fseek( fp, 0, SEEK_END );
1700 size_t size = ftell( fp );
1701 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001702
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001704 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001707
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 _charBuffer = new char[size+1];
1709 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 if ( read != size ) {
1711 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001712 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001714
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001716
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 if ( !p || !*p ) {
1721 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001724
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1726 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727}
1728
1729
Lee Thomason2fa81722012-11-09 12:37:46 -08001730XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 FILE* fp = 0;
1733#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1734 errno_t err = fopen_s(&fp, filename, "w" );
1735 if ( !fp || err) {
1736#else
1737 fp = fopen( filename, "w" );
1738 if ( !fp) {
1739#endif
1740 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 }
1743 SaveFile(fp, compact);
1744 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001746}
1747
1748
Lee Thomason2fa81722012-11-09 12:37:46 -08001749XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 XMLPrinter stream( fp, compact );
1752 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001754}
1755
Lee Thomason1ff38e02012-02-14 18:18:16 -08001756
Lee Thomason2fa81722012-11-09 12:37:46 -08001757XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001758{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001759 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001760 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001761
psi690ba072013-11-03 10:54:33 +09001762 if ( len == 0 ) {
1763 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1764 return _errorID;
1765 }
1766
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 if ( !p || !*p ) {
1768 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
1771 if ( len == (size_t)(-1) ) {
1772 len = strlen( p );
1773 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 _charBuffer = new char[ len+1 ];
1775 memcpy( _charBuffer, p, len );
1776 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001777
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 if ( !p || !*p ) {
1781 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001784
Thomas Roß1470edc2013-05-10 15:44:12 +02001785 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001786 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001788}
1789
1790
PKEuS1c5f99e2013-07-06 11:28:39 +02001791void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001792{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 XMLPrinter stdStreamer( stdout );
1794 if ( !streamer ) {
1795 streamer = &stdStreamer;
1796 }
1797 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001798}
1799
1800
Lee Thomason2fa81722012-11-09 12:37:46 -08001801void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001802{
Lee Thomason624d43f2012-10-12 10:58:48 -07001803 _errorID = error;
1804 _errorStr1 = str1;
1805 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001806}
1807
Lee Thomason5cae8972012-01-24 18:03:07 -08001808
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001809void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810{
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 static const int LEN = 20;
1813 char buf1[LEN] = { 0 };
1814 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001815
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 if ( _errorStr1 ) {
1817 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 if ( _errorStr2 ) {
1820 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001822
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826}
1827
1828
PKEuS1bfb9542013-08-04 13:51:17 +02001829XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _elementJustOpened( false ),
1831 _firstElement( true ),
1832 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001833 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 _textDepth( -1 ),
1835 _processEntities( true ),
1836 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001837{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _entityFlag[i] = false;
1840 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 }
1842 for( int i=0; i<NUM_ENTITIES; ++i ) {
1843 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1844 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 }
1847 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 _restrictedEntityFlag[(int)'&'] = true;
1849 _restrictedEntityFlag[(int)'<'] = true;
1850 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1851 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001852}
1853
1854
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001855void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001856{
1857 va_list va;
1858 va_start( va, format );
1859
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 if ( _fp ) {
1861 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 }
1863 else {
1864 // This seems brutally complex. Haven't figured out a better
1865 // way on windows.
1866#ifdef _MSC_VER
1867 int len = -1;
1868 int expand = 1000;
1869 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 if ( len < 0 ) {
1872 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001873 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 }
1875 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 char* p = _buffer.PushArr( len ) - 1;
1877 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878#else
1879 int len = vsnprintf( 0, 0, format, va );
1880 // Close out and re-start the va-args
1881 va_end( va );
1882 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 vsnprintf( p, len+1, format, va );
1885#endif
1886 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001887 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001888}
1889
1890
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001891void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001892{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 for( int i=0; i<depth; ++i ) {
1894 Print( " " );
1895 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001896}
1897
1898
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001899void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 // Look for runs of bytes between entities to print.
1902 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001904
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 while ( *q ) {
1907 // Remember, char is sometimes signed. (How many times has that bitten me?)
1908 if ( *q > 0 && *q < ENTITY_RANGE ) {
1909 // Check for entities. If one is found, flush
1910 // the stream up until the entity, write the
1911 // entity, and keep looking.
1912 if ( flag[(unsigned)(*q)] ) {
1913 while ( p < q ) {
1914 Print( "%c", *p );
1915 ++p;
1916 }
1917 for( int i=0; i<NUM_ENTITIES; ++i ) {
1918 if ( entities[i].value == *q ) {
1919 Print( "&%s;", entities[i].pattern );
1920 break;
1921 }
1922 }
1923 ++p;
1924 }
1925 }
1926 ++q;
1927 }
1928 }
1929 // Flush the remaining string. This will be the entire
1930 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001931 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 Print( "%s", p );
1933 }
Lee Thomason857b8682012-01-25 17:50:25 -08001934}
1935
U-Stream\Leeae25a442012-02-17 17:48:16 -08001936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001940 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 -07001941 Print( "%s", bom );
1942 }
1943 if ( writeDec ) {
1944 PushDeclaration( "xml version=\"1.0\"" );
1945 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001946}
1947
1948
Uli Kustererd5c9e8b2014-02-01 12:48:51 +01001949void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001950{
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 SealElement();
1953 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001955
Uli Kustererd5c9e8b2014-02-01 12:48:51 +01001956 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001958 }
Uli Kustererd5c9e8b2014-02-01 12:48:51 +01001959 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001962
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _elementJustOpened = true;
1965 _firstElement = false;
1966 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001967}
1968
1969
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001970void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001971{
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 Print( " %s=\"", name );
1974 PrintString( value, false );
1975 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001976}
1977
1978
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001979void XMLPrinter::PushAttribute( const char* name, int v )
1980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 char buf[BUF_SIZE];
1982 XMLUtil::ToStr( v, buf, BUF_SIZE );
1983 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001984}
1985
1986
1987void XMLPrinter::PushAttribute( const char* name, unsigned v )
1988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 char buf[BUF_SIZE];
1990 XMLUtil::ToStr( v, buf, BUF_SIZE );
1991 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001992}
1993
1994
1995void XMLPrinter::PushAttribute( const char* name, bool v )
1996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 char buf[BUF_SIZE];
1998 XMLUtil::ToStr( v, buf, BUF_SIZE );
1999 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002000}
2001
2002
2003void XMLPrinter::PushAttribute( const char* name, double v )
2004{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 char buf[BUF_SIZE];
2006 XMLUtil::ToStr( v, buf, BUF_SIZE );
2007 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002008}
2009
2010
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002011void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002012{
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 --_depth;
2014 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002015
Lee Thomason624d43f2012-10-12 10:58:48 -07002016 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 Print( "/>" );
2018 }
2019 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 }
2024 Print( "</%s>", name );
2025 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002026
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 if ( _textDepth == _depth ) {
2028 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 Print( "\n" );
2032 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002034}
2035
2036
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002037void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002038{
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002041}
2042
2043
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002044void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002045{
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002047
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 SealElement();
2050 }
2051 if ( cdata ) {
2052 Print( "<![CDATA[" );
2053 Print( "%s", text );
2054 Print( "]]>" );
2055 }
2056 else {
2057 PrintString( text, true );
2058 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002059}
2060
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002061void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 char buf[BUF_SIZE];
2064 XMLUtil::ToStr( value, buf, BUF_SIZE );
2065 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002066}
2067
2068
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002069void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 char buf[BUF_SIZE];
2072 XMLUtil::ToStr( value, buf, BUF_SIZE );
2073 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002074}
2075
2076
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002077void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 char buf[BUF_SIZE];
2080 XMLUtil::ToStr( value, buf, BUF_SIZE );
2081 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002082}
2083
2084
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002085void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002086{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 char buf[BUF_SIZE];
2088 XMLUtil::ToStr( value, buf, BUF_SIZE );
2089 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002090}
2091
2092
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002093void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 char buf[BUF_SIZE];
2096 XMLUtil::ToStr( value, buf, BUF_SIZE );
2097 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002098}
2099
Lee Thomason5cae8972012-01-24 18:03:07 -08002100
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002101void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002102{
Lee Thomason624d43f2012-10-12 10:58:48 -07002103 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 SealElement();
2105 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002106 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002108 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002112}
Lee Thomason751da522012-02-10 08:50:51 -08002113
2114
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002115void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002116{
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 SealElement();
2119 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002126}
2127
2128
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002129void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002130{
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 SealElement();
2133 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002140}
2141
2142
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002143bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002144{
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 if ( doc.HasBOM() ) {
2147 PushHeader( true, false );
2148 }
2149 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002150}
2151
2152
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002153bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002154{
Uli Kustererd5c9e8b2014-02-01 12:48:51 +01002155 OpenElement( element.Name(), _compactMode ? true : element.Parent()->GetForceCompactMode() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 while ( attribute ) {
2157 PushAttribute( attribute->Name(), attribute->Value() );
2158 attribute = attribute->Next();
2159 }
2160 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002161}
2162
2163
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002164bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 CloseElement();
2167 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002168}
2169
2170
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002171bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 PushText( text.Value(), text.CData() );
2174 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002175}
2176
2177
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002178bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 PushComment( comment.Value() );
2181 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002182}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002183
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002184bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 PushDeclaration( declaration.Value() );
2187 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188}
2189
2190
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002191bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 PushUnknown( unknown.Value() );
2194 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002195}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002196
Lee Thomason685b8952012-11-12 13:00:06 -08002197} // namespace tinyxml2
2198