blob: b890cb1267e826197b40ea33a4d935413cdda7fc [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
425
426void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
427{
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700428 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700429}
430
431
432void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
433{
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700434 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700435}
436
437
438bool XMLUtil::ToInt( const char* str, int* value )
439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
441 return true;
442 }
443 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700444}
445
446bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700448 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
449 return true;
450 }
451 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454bool XMLUtil::ToBool( const char* str, bool* value )
455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 int ival = 0;
457 if ( ToInt( str, &ival )) {
458 *value = (ival==0) ? false : true;
459 return true;
460 }
461 if ( StringEqual( str, "true" ) ) {
462 *value = true;
463 return true;
464 }
465 else if ( StringEqual( str, "false" ) ) {
466 *value = false;
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472
473bool XMLUtil::ToFloat( const char* str, float* value )
474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
476 return true;
477 }
478 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700479}
480
481bool XMLUtil::ToDouble( const char* str, double* value )
482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700490char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 XMLNode* returnNode = 0;
493 char* start = p;
494 p = XMLUtil::SkipWhiteSpace( p );
495 if( !p || !*p ) {
496 return p;
497 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 // What is this thing?
500 // - Elements start with a letter or underscore, but xml is reserved.
501 // - Comments: <!--
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700502 // - Declaration: <?
503 // - Everything else is unknown to tinyxml.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 static const char* xmlHeader = { "<?" };
507 static const char* commentHeader = { "<!--" };
508 static const char* dtdHeader = { "<!" };
509 static const char* cdataHeader = { "<![CDATA[" };
510 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 static const int xmlHeaderLen = 2;
513 static const int commentHeaderLen = 4;
514 static const int dtdHeaderLen = 2;
515 static const int cdataHeaderLen = 9;
516 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800518#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800519#pragma warning ( push )
520#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800521#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
523 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800525#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700528 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
529 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 p += xmlHeaderLen;
531 }
532 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode = new (_commentPool.Alloc()) XMLComment( this );
534 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 p += commentHeaderLen;
536 }
537 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 p += cdataHeaderLen;
542 text->SetCData( true );
543 }
544 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += dtdHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 returnNode = new (_elementPool.Alloc()) XMLElement( this );
551 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += elementHeaderLen;
553 }
554 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_textPool.Alloc()) XMLText( this );
556 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p = start; // Back it up, all the text counts.
558 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800559
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 *node = returnNode;
561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562}
563
564
Lee Thomason751da522012-02-10 08:50:51 -0800565bool XMLDocument::Accept( XMLVisitor* visitor ) const
566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( visitor->VisitEnter( *this ) ) {
568 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
569 if ( !node->Accept( visitor ) ) {
570 break;
571 }
572 }
573 }
574 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800575}
Lee Thomason56bdd022012-02-09 18:16:58 -0800576
577
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800578// --------- XMLNode ----------- //
579
580XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 _document( doc ),
582 _parent( 0 ),
583 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200584 _prev( 0 ), _next( 0 ),
585 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587}
588
589
590XMLNode::~XMLNode()
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 if ( _parent ) {
594 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800596}
597
Michael Daumling21626882013-10-22 17:03:37 +0200598const char* XMLNode::Value() const
599{
600 return _value.GetStr();
601}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800602
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603void XMLNode::SetValue( const char* str, bool staticMem )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
608 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800611}
612
613
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800614void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800615{
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 while( _firstChild ) {
617 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700619
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 DELETE_NODE( node );
621 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700622 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800623}
624
625
626void XMLNode::Unlink( XMLNode* child )
627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 TIXMLASSERT( child->_parent == this );
629 if ( child == _firstChild ) {
630 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 if ( child == _lastChild ) {
633 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
Lee Thomasond923c672012-01-23 08:44:25 -0800635
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 if ( child->_prev ) {
637 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 if ( child->_next ) {
640 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800643}
644
645
U-Stream\Leeae25a442012-02-17 17:48:16 -0800646void XMLNode::DeleteChild( XMLNode* node )
647{
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800650}
651
652
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
654{
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( _lastChild ) {
656 TIXMLASSERT( _firstChild );
657 TIXMLASSERT( _lastChild->_next == 0 );
658 _lastChild->_next = addThis;
659 addThis->_prev = _lastChild;
660 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 }
664 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( _firstChild == 0 );
666 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_prev = 0;
669 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800672 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674}
675
676
Lee Thomason1ff38e02012-02-14 18:18:16 -0800677XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
678{
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 if ( _firstChild ) {
680 TIXMLASSERT( _lastChild );
681 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 _firstChild->_prev = addThis;
684 addThis->_next = _firstChild;
685 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 }
689 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 TIXMLASSERT( _lastChild == 0 );
691 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_prev = 0;
694 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800697 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800699}
700
701
702XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
703{
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 TIXMLASSERT( afterThis->_parent == this );
705 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 return 0;
707 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 // The last node or the only node.
711 return InsertEndChild( addThis );
712 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 addThis->_prev = afterThis;
714 addThis->_next = afterThis->_next;
715 afterThis->_next->_prev = addThis;
716 afterThis->_next = addThis;
717 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800718 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700719 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720}
721
722
723
724
Lee Thomason56bdd022012-02-09 18:16:58 -0800725const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800726{
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 XMLElement* element = node->ToElement();
729 if ( element ) {
730 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
731 return element;
732 }
733 }
734 }
735 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800736}
737
738
Lee Thomason56bdd022012-02-09 18:16:58 -0800739const XMLElement* XMLNode::LastChildElement( const char* value ) const
740{
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700742 XMLElement* element = node->ToElement();
743 if ( element ) {
744 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
745 return element;
746 }
747 }
748 }
749 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800750}
751
752
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800753const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
754{
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 if ( element->ToElement()
757 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
758 return element->ToElement();
759 }
760 }
761 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800762}
763
764
765const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
766{
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 if ( element->ToElement()
769 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
770 return element->ToElement();
771 }
772 }
773 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800774}
775
776
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800777char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800778{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 // This is a recursive method, but thinking about it "at the current level"
780 // it is a pretty simple flat list:
781 // <foo/>
782 // <!-- comment -->
783 //
784 // With a special case:
785 // <foo>
786 // </foo>
787 // <!-- comment -->
788 //
789 // Where the closing element (/foo) *must* be the next thing after the opening
790 // element, and the names must match. BUT the tricky bit is that the closing
791 // element will be read by the child.
792 //
793 // 'endTag' is the end tag for this node, it is returned by a call to a child.
794 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800795
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 while( p && *p ) {
797 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800798
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 if ( p == 0 || node == 0 ) {
801 break;
802 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800803
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 StrPair endTag;
805 p = node->ParseDeep( p, &endTag );
806 if ( !p ) {
807 DELETE_NODE( node );
808 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( !_document->Error() ) {
810 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
812 break;
813 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800814
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 // We read the end tag. Return it to the parent.
816 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
817 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800820 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 DELETE_NODE( node );
822 return p;
823 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800824
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 // Handle an end tag returned to this level.
826 // And handle a bunch of annoying errors.
827 XMLElement* ele = node->ToElement();
828 if ( ele ) {
829 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 p = 0;
832 }
833 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 p = 0;
836 }
837 else if ( !endTag.Empty() ) {
838 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 p = 0;
841 }
842 }
843 }
844 if ( p == 0 ) {
845 DELETE_NODE( node );
846 node = 0;
847 }
848 if ( node ) {
849 this->InsertEndChild( node );
850 }
851 }
852 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800853}
854
Lee Thomason5492a1c2012-01-23 15:32:10 -0800855// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800856char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800857{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 const char* start = p;
859 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
864 return p;
865 }
866 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
868 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 flags |= StrPair::COLLAPSE_WHITESPACE;
870 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 }
876 if ( p && *p ) {
877 return p-1;
878 }
879 }
880 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800881}
882
883
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800884XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
885{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
890 text->SetCData( this->CData() );
891 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800892}
893
894
895bool XMLText::ShallowEqual( const XMLNode* compare ) const
896{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800898}
899
900
Lee Thomason56bdd022012-02-09 18:16:58 -0800901bool XMLText::Accept( XMLVisitor* visitor ) const
902{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800904}
905
906
Lee Thomason3f57d272012-01-11 15:30:03 -0800907// --------- XMLComment ---------- //
908
Lee Thomasone4422302012-01-20 17:59:50 -0800909XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800910{
911}
912
913
Lee Thomasonce0763e2012-01-11 15:43:54 -0800914XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800915{
Lee Thomason3f57d272012-01-11 15:30:03 -0800916}
917
918
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800919char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800920{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 // Comment parses as text.
922 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700925 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 }
927 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800928}
929
930
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800931XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
932{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 }
936 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
937 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938}
939
940
941bool XMLComment::ShallowEqual( const XMLNode* compare ) const
942{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800944}
945
946
Lee Thomason751da522012-02-10 08:50:51 -0800947bool XMLComment::Accept( XMLVisitor* visitor ) const
948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800950}
Lee Thomason56bdd022012-02-09 18:16:58 -0800951
952
Lee Thomason50f97b22012-02-11 16:33:40 -0800953// --------- XMLDeclaration ---------- //
954
955XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
956{
957}
958
959
960XMLDeclaration::~XMLDeclaration()
961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800963}
964
965
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800966char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800967{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 // Declaration parses as text.
969 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700970 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700972 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 }
974 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800975}
976
977
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800978XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
984 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
988bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800991}
992
993
994
Lee Thomason50f97b22012-02-11 16:33:40 -0800995bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800998}
999
1000// --------- XMLUnknown ---------- //
1001
1002XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1003{
1004}
1005
1006
1007XMLUnknown::~XMLUnknown()
1008{
1009}
1010
1011
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001012char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001013{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 // Unknown parses as text.
1015 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001016
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001019 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 }
1021 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001022}
1023
1024
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001025XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001028 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 }
1030 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1031 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001032}
1033
1034
1035bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001038}
1039
1040
Lee Thomason50f97b22012-02-11 16:33:40 -08001041bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001044}
1045
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001046// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001047
1048const char* XMLAttribute::Name() const
1049{
1050 return _name.GetStr();
1051}
1052
1053const char* XMLAttribute::Value() const
1054{
1055 return _value.GetStr();
1056}
1057
Lee Thomason6f381b72012-03-02 12:59:39 -08001058char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001061 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 if ( !p || !*p ) {
1063 return 0;
1064 }
Lee Thomason22aead12012-01-23 13:29:35 -08001065
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 // Skip white space before =
1067 p = XMLUtil::SkipWhiteSpace( p );
1068 if ( !p || *p != '=' ) {
1069 return 0;
1070 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001071
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 ++p; // move up to opening quote
1073 p = XMLUtil::SkipWhiteSpace( p );
1074 if ( *p != '\"' && *p != '\'' ) {
1075 return 0;
1076 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001077
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 char endTag[2] = { *p, 0 };
1079 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001080
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001083}
1084
1085
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001086void XMLAttribute::SetName( const char* n )
1087{
Lee Thomason624d43f2012-10-12 10:58:48 -07001088 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001089}
1090
1091
Lee Thomason2fa81722012-11-09 12:37:46 -08001092XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( XMLUtil::ToInt( Value(), value )) {
1095 return XML_NO_ERROR;
1096 }
1097 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001098}
1099
1100
Lee Thomason2fa81722012-11-09 12:37:46 -08001101XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 if ( XMLUtil::ToUnsigned( Value(), value )) {
1104 return XML_NO_ERROR;
1105 }
1106 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001107}
1108
1109
Lee Thomason2fa81722012-11-09 12:37:46 -08001110XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( XMLUtil::ToBool( Value(), value )) {
1113 return XML_NO_ERROR;
1114 }
1115 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001116}
1117
1118
Lee Thomason2fa81722012-11-09 12:37:46 -08001119XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001120{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 if ( XMLUtil::ToFloat( Value(), value )) {
1122 return XML_NO_ERROR;
1123 }
1124 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001125}
1126
1127
Lee Thomason2fa81722012-11-09 12:37:46 -08001128XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( XMLUtil::ToDouble( Value(), value )) {
1131 return XML_NO_ERROR;
1132 }
1133 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001134}
1135
1136
1137void XMLAttribute::SetAttribute( const char* v )
1138{
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140}
1141
1142
Lee Thomason1ff38e02012-02-14 18:18:16 -08001143void XMLAttribute::SetAttribute( int v )
1144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 char buf[BUF_SIZE];
1146 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001147 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001148}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001149
1150
1151void XMLAttribute::SetAttribute( unsigned v )
1152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 char buf[BUF_SIZE];
1154 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001156}
1157
1158
1159void XMLAttribute::SetAttribute( bool v )
1160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 char buf[BUF_SIZE];
1162 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001164}
1165
1166void XMLAttribute::SetAttribute( double v )
1167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 char buf[BUF_SIZE];
1169 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001170 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001171}
1172
1173void XMLAttribute::SetAttribute( float v )
1174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 char buf[BUF_SIZE];
1176 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001178}
1179
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001180
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001181// --------- XMLElement ---------- //
1182XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _closingType( 0 ),
1184 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001185{
1186}
1187
1188
1189XMLElement::~XMLElement()
1190{
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 while( _rootAttribute ) {
1192 XMLAttribute* next = _rootAttribute->_next;
1193 DELETE_ATTRIBUTE( _rootAttribute );
1194 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001196}
1197
1198
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001199XMLAttribute* XMLElement::FindAttribute( const char* name )
1200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1204 return a;
1205 }
1206 }
1207 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001208}
1209
1210
1211const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1216 return a;
1217 }
1218 }
1219 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001220}
1221
1222
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001223const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 const XMLAttribute* a = FindAttribute( name );
1226 if ( !a ) {
1227 return 0;
1228 }
1229 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1230 return a->Value();
1231 }
1232 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001233}
1234
1235
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001236const char* XMLElement::GetText() const
1237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 if ( FirstChild() && FirstChild()->ToText() ) {
1239 return FirstChild()->ToText()->Value();
1240 }
1241 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001242}
1243
1244
MortenMacFly4ee49f12013-01-14 20:03:14 +01001245XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( FirstChild() && FirstChild()->ToText() ) {
1248 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001249 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 return XML_SUCCESS;
1251 }
1252 return XML_CAN_NOT_CONVERT_TEXT;
1253 }
1254 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001255}
1256
1257
MortenMacFly4ee49f12013-01-14 20:03:14 +01001258XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( FirstChild() && FirstChild()->ToText() ) {
1261 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001262 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 return XML_SUCCESS;
1264 }
1265 return XML_CAN_NOT_CONVERT_TEXT;
1266 }
1267 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001268}
1269
1270
MortenMacFly4ee49f12013-01-14 20:03:14 +01001271XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( FirstChild() && FirstChild()->ToText() ) {
1274 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001275 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 return XML_SUCCESS;
1277 }
1278 return XML_CAN_NOT_CONVERT_TEXT;
1279 }
1280 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001281}
1282
1283
MortenMacFly4ee49f12013-01-14 20:03:14 +01001284XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( FirstChild() && FirstChild()->ToText() ) {
1287 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001288 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 return XML_SUCCESS;
1290 }
1291 return XML_CAN_NOT_CONVERT_TEXT;
1292 }
1293 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001294}
1295
1296
MortenMacFly4ee49f12013-01-14 20:03:14 +01001297XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 if ( FirstChild() && FirstChild()->ToText() ) {
1300 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001301 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 return XML_SUCCESS;
1303 }
1304 return XML_CAN_NOT_CONVERT_TEXT;
1305 }
1306 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001307}
1308
1309
1310
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001311XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 XMLAttribute* last = 0;
1314 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001315 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001317 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1319 break;
1320 }
1321 }
1322 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001323 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1324 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001325 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001326 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 }
1328 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001329 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001332 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 }
1334 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001335}
1336
1337
U-Stream\Leeae25a442012-02-17 17:48:16 -08001338void XMLElement::DeleteAttribute( const char* name )
1339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001341 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1343 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001344 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 }
1346 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001347 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 }
1349 DELETE_ATTRIBUTE( a );
1350 break;
1351 }
1352 prev = a;
1353 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001354}
1355
1356
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001357char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 const char* start = p;
1360 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001361
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 // Read the attributes.
1363 while( p ) {
1364 p = XMLUtil::SkipWhiteSpace( p );
1365 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001366 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 return 0;
1368 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001369
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001371 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1373 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001374 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001375
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 if ( !p || Attribute( attrib->Name() ) ) {
1378 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001379 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 return 0;
1381 }
1382 // There is a minor bug here: if the attribute in the source xml
1383 // document is duplicated, it will not be detected and the
1384 // attribute will be doubly added. However, tracking the 'prevAttribute'
1385 // avoids re-scanning the attribute list. Preferring performance for
1386 // now, may reconsider in the future.
1387 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 }
1390 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001391 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 }
1393 prevAttribute = attrib;
1394 }
1395 // end of the tag
1396 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001397 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 return p+2; // done; sealed element.
1399 }
1400 // end of the tag
1401 else if ( *p == '>' ) {
1402 ++p;
1403 break;
1404 }
1405 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return 0;
1408 }
1409 }
1410 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001411}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001412
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001413
Lee Thomason67d61312012-01-24 16:01:51 -08001414//
1415// <ele></ele>
1416// <ele>foo<b>bar</b></ele>
1417//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001418char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 // Read the element name.
1421 p = XMLUtil::SkipWhiteSpace( p );
1422 if ( !p ) {
1423 return 0;
1424 }
Lee Thomason67d61312012-01-24 16:01:51 -08001425
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 // The closing element is the </element> form. It is
1427 // parsed just like a regular element then deleted from
1428 // the DOM.
1429 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 ++p;
1432 }
Lee Thomason67d61312012-01-24 16:01:51 -08001433
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 p = _value.ParseName( p );
1435 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 return 0;
1437 }
Lee Thomason67d61312012-01-24 16:01:51 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 return p;
1442 }
Lee Thomason67d61312012-01-24 16:01:51 -08001443
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 p = XMLNode::ParseDeep( p, strPair );
1445 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001446}
1447
1448
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001449
1450XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
1455 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1456 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1457 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1458 }
1459 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001460}
1461
1462
1463bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 const XMLElement* other = compare->ToElement();
1466 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001467
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 const XMLAttribute* a=FirstAttribute();
1469 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001470
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 while ( a && b ) {
1472 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1473 return false;
1474 }
1475 a = a->Next();
1476 b = b->Next();
1477 }
1478 if ( a || b ) {
1479 // different count
1480 return false;
1481 }
1482 return true;
1483 }
1484 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001485}
1486
1487
Lee Thomason751da522012-02-10 08:50:51 -08001488bool XMLElement::Accept( XMLVisitor* visitor ) const
1489{
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1492 if ( !node->Accept( visitor ) ) {
1493 break;
1494 }
1495 }
1496 }
1497 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001498}
Lee Thomason56bdd022012-02-09 18:16:58 -08001499
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001500
Lee Thomason3f57d272012-01-11 15:30:03 -08001501// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001502XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _writeBOM( false ),
1505 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001506 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _whitespace( whitespace ),
1508 _errorStr1( 0 ),
1509 _errorStr2( 0 ),
1510 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001511{
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001513}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001514
1515
Lee Thomason3f57d272012-01-11 15:30:03 -08001516XMLDocument::~XMLDocument()
1517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001520
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001521#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001522 _textPool.Trace( "text" );
1523 _elementPool.Trace( "element" );
1524 _commentPool.Trace( "comment" );
1525 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001526#endif
1527
Lee Thomason5b0a6772012-11-19 13:54:42 -08001528#ifdef DEBUG
1529 if ( Error() == false ) {
1530 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1531 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1532 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1533 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1534 }
1535#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001536}
1537
1538
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001539void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001540{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001541 DeleteChildren();
1542
Lee Thomason624d43f2012-10-12 10:58:48 -07001543 _errorID = XML_NO_ERROR;
1544 _errorStr1 = 0;
1545 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001546
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 delete [] _charBuffer;
1548 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001549}
1550
Lee Thomason3f57d272012-01-11 15:30:03 -08001551
Lee Thomason2c85a712012-01-31 08:24:24 -08001552XMLElement* XMLDocument::NewElement( const char* name )
1553{
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1555 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 ele->SetName( name );
1557 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001558}
1559
1560
Lee Thomason1ff38e02012-02-14 18:18:16 -08001561XMLComment* XMLDocument::NewComment( const char* str )
1562{
Lee Thomason624d43f2012-10-12 10:58:48 -07001563 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1564 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 comment->SetValue( str );
1566 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001567}
1568
1569
1570XMLText* XMLDocument::NewText( const char* str )
1571{
Lee Thomason624d43f2012-10-12 10:58:48 -07001572 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1573 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 text->SetValue( str );
1575 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001576}
1577
1578
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1580{
Lee Thomason624d43f2012-10-12 10:58:48 -07001581 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1582 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1584 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001585}
1586
1587
1588XMLUnknown* XMLDocument::NewUnknown( const char* str )
1589{
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1591 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 unk->SetValue( str );
1593 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001594}
1595
1596
Lee Thomason2fa81722012-11-09 12:37:46 -08001597XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001598{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001599 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001601
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1603 errno_t err = fopen_s(&fp, filename, "rb" );
1604 if ( !fp || err) {
1605#else
1606 fp = fopen( filename, "rb" );
1607 if ( !fp) {
1608#endif
1609 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 }
1612 LoadFile( fp );
1613 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001615}
1616
1617
Lee Thomason2fa81722012-11-09 12:37:46 -08001618XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001619{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001620 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001621
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 fseek( fp, 0, SEEK_END );
1623 size_t size = ftell( fp );
1624 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001625
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001627 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001630
Lee Thomason624d43f2012-10-12 10:58:48 -07001631 _charBuffer = new char[size+1];
1632 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 if ( read != size ) {
1634 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001637
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001639
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001642 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 if ( !p || !*p ) {
1644 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001647
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1649 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001650}
1651
1652
Lee Thomason2fa81722012-11-09 12:37:46 -08001653XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001654{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 FILE* fp = 0;
1656#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1657 errno_t err = fopen_s(&fp, filename, "w" );
1658 if ( !fp || err) {
1659#else
1660 fp = fopen( filename, "w" );
1661 if ( !fp) {
1662#endif
1663 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 }
1666 SaveFile(fp, compact);
1667 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001669}
1670
1671
Lee Thomason2fa81722012-11-09 12:37:46 -08001672XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001673{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 XMLPrinter stream( fp, compact );
1675 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001677}
1678
Lee Thomason1ff38e02012-02-14 18:18:16 -08001679
Lee Thomason2fa81722012-11-09 12:37:46 -08001680XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001681{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001682 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001683 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001684
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 if ( !p || !*p ) {
1686 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 }
1689 if ( len == (size_t)(-1) ) {
1690 len = strlen( p );
1691 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 _charBuffer = new char[ len+1 ];
1693 memcpy( _charBuffer, p, len );
1694 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001695
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 if ( !p || !*p ) {
1699 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001702
Thomas Roß1470edc2013-05-10 15:44:12 +02001703 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001704 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001706}
1707
1708
PKEuS1c5f99e2013-07-06 11:28:39 +02001709void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 XMLPrinter stdStreamer( stdout );
1712 if ( !streamer ) {
1713 streamer = &stdStreamer;
1714 }
1715 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001716}
1717
1718
Lee Thomason2fa81722012-11-09 12:37:46 -08001719void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001720{
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 _errorID = error;
1722 _errorStr1 = str1;
1723 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001724}
1725
Lee Thomason5cae8972012-01-24 18:03:07 -08001726
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001727void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728{
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 static const int LEN = 20;
1731 char buf1[LEN] = { 0 };
1732 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001733
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 if ( _errorStr1 ) {
1735 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 if ( _errorStr2 ) {
1738 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001740
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001744}
1745
1746
PKEuS1bfb9542013-08-04 13:51:17 +02001747XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 _elementJustOpened( false ),
1749 _firstElement( true ),
1750 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001751 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 _textDepth( -1 ),
1753 _processEntities( true ),
1754 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 _entityFlag[i] = false;
1758 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 }
1760 for( int i=0; i<NUM_ENTITIES; ++i ) {
1761 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1762 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 }
1765 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 _restrictedEntityFlag[(int)'&'] = true;
1767 _restrictedEntityFlag[(int)'<'] = true;
1768 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1769 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001770}
1771
1772
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001773void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001774{
1775 va_list va;
1776 va_start( va, format );
1777
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 if ( _fp ) {
1779 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 }
1781 else {
1782 // This seems brutally complex. Haven't figured out a better
1783 // way on windows.
1784#ifdef _MSC_VER
1785 int len = -1;
1786 int expand = 1000;
1787 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( len < 0 ) {
1790 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001791 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
1793 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 char* p = _buffer.PushArr( len ) - 1;
1795 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796#else
1797 int len = vsnprintf( 0, 0, format, va );
1798 // Close out and re-start the va-args
1799 va_end( va );
1800 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 vsnprintf( p, len+1, format, va );
1803#endif
1804 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001805 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001806}
1807
1808
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001809void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001810{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 for( int i=0; i<depth; ++i ) {
1812 Print( " " );
1813 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001814}
1815
1816
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001817void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001818{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 // Look for runs of bytes between entities to print.
1820 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001822
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 while ( *q ) {
1825 // Remember, char is sometimes signed. (How many times has that bitten me?)
1826 if ( *q > 0 && *q < ENTITY_RANGE ) {
1827 // Check for entities. If one is found, flush
1828 // the stream up until the entity, write the
1829 // entity, and keep looking.
1830 if ( flag[(unsigned)(*q)] ) {
1831 while ( p < q ) {
1832 Print( "%c", *p );
1833 ++p;
1834 }
1835 for( int i=0; i<NUM_ENTITIES; ++i ) {
1836 if ( entities[i].value == *q ) {
1837 Print( "&%s;", entities[i].pattern );
1838 break;
1839 }
1840 }
1841 ++p;
1842 }
1843 }
1844 ++q;
1845 }
1846 }
1847 // Flush the remaining string. This will be the entire
1848 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 Print( "%s", p );
1851 }
Lee Thomason857b8682012-01-25 17:50:25 -08001852}
1853
U-Stream\Leeae25a442012-02-17 17:48:16 -08001854
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001855void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001856{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001858 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 -07001859 Print( "%s", bom );
1860 }
1861 if ( writeDec ) {
1862 PushDeclaration( "xml version=\"1.0\"" );
1863 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001864}
1865
1866
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001867void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001868{
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 SealElement();
1871 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001873
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001876 }
1877 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001878 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001880
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 _elementJustOpened = true;
1883 _firstElement = false;
1884 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001885}
1886
1887
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001888void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001889{
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 Print( " %s=\"", name );
1892 PrintString( value, false );
1893 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001894}
1895
1896
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001897void XMLPrinter::PushAttribute( const char* name, int v )
1898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 char buf[BUF_SIZE];
1900 XMLUtil::ToStr( v, buf, BUF_SIZE );
1901 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001902}
1903
1904
1905void XMLPrinter::PushAttribute( const char* name, unsigned v )
1906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 char buf[BUF_SIZE];
1908 XMLUtil::ToStr( v, buf, BUF_SIZE );
1909 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001910}
1911
1912
1913void XMLPrinter::PushAttribute( const char* name, bool v )
1914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 char buf[BUF_SIZE];
1916 XMLUtil::ToStr( v, buf, BUF_SIZE );
1917 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918}
1919
1920
1921void XMLPrinter::PushAttribute( const char* name, double v )
1922{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 char buf[BUF_SIZE];
1924 XMLUtil::ToStr( v, buf, BUF_SIZE );
1925 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001926}
1927
1928
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001929void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001930{
Lee Thomason624d43f2012-10-12 10:58:48 -07001931 --_depth;
1932 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001933
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 Print( "/>" );
1936 }
1937 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 }
1942 Print( "</%s>", name );
1943 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001944
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 if ( _textDepth == _depth ) {
1946 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 Print( "\n" );
1950 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001952}
1953
1954
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001955void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001956{
Lee Thomason624d43f2012-10-12 10:58:48 -07001957 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001959}
1960
1961
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001962void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001963{
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001965
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 SealElement();
1968 }
1969 if ( cdata ) {
1970 Print( "<![CDATA[" );
1971 Print( "%s", text );
1972 Print( "]]>" );
1973 }
1974 else {
1975 PrintString( text, true );
1976 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001977}
1978
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001979void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 char buf[BUF_SIZE];
1982 XMLUtil::ToStr( value, buf, BUF_SIZE );
1983 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001984}
1985
1986
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001987void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 char buf[BUF_SIZE];
1990 XMLUtil::ToStr( value, buf, BUF_SIZE );
1991 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001992}
1993
1994
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001995void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 char buf[BUF_SIZE];
1998 XMLUtil::ToStr( value, buf, BUF_SIZE );
1999 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002000}
2001
2002
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002003void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002004{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 char buf[BUF_SIZE];
2006 XMLUtil::ToStr( value, buf, BUF_SIZE );
2007 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002008}
2009
2010
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002011void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002012{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 char buf[BUF_SIZE];
2014 XMLUtil::ToStr( value, buf, BUF_SIZE );
2015 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002016}
2017
Lee Thomason5cae8972012-01-24 18:03:07 -08002018
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002019void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002020{
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 SealElement();
2023 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002030}
Lee Thomason751da522012-02-10 08:50:51 -08002031
2032
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002033void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002034{
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 SealElement();
2037 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002038 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002044}
2045
2046
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002047void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002048{
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 SealElement();
2051 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002056 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002058}
2059
2060
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002061bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002062{
Lee Thomason624d43f2012-10-12 10:58:48 -07002063 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 if ( doc.HasBOM() ) {
2065 PushHeader( true, false );
2066 }
2067 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002068}
2069
2070
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002071bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 OpenElement( element.Name() );
2074 while ( attribute ) {
2075 PushAttribute( attribute->Name(), attribute->Value() );
2076 attribute = attribute->Next();
2077 }
2078 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002079}
2080
2081
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002082bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 CloseElement();
2085 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002086}
2087
2088
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002089bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 PushText( text.Value(), text.CData() );
2092 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002093}
2094
2095
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002096bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002097{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 PushComment( comment.Value() );
2099 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002100}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002101
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002102bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 PushDeclaration( declaration.Value() );
2105 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002106}
2107
2108
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002109bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 PushUnknown( unknown.Value() );
2112 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002113}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002114
Lee Thomason685b8952012-11-12 13:00:06 -08002115} // namespace tinyxml2
2116