blob: c13713fa7dd3fdb208ab1e5bdb7ff605318828bf [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 ),
584 _prev( 0 ), _next( 0 )
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
597
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800598void XMLNode::SetValue( const char* str, bool staticMem )
599{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700600 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 }
603 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800606}
607
608
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800609void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610{
Lee Thomason624d43f2012-10-12 10:58:48 -0700611 while( _firstChild ) {
612 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700614
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 DELETE_NODE( node );
616 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800618}
619
620
621void XMLNode::Unlink( XMLNode* child )
622{
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 TIXMLASSERT( child->_parent == this );
624 if ( child == _firstChild ) {
625 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700626 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 if ( child == _lastChild ) {
628 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomasond923c672012-01-23 08:44:25 -0800630
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( child->_prev ) {
632 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 if ( child->_next ) {
635 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800638}
639
640
U-Stream\Leeae25a442012-02-17 17:48:16 -0800641void XMLNode::DeleteChild( XMLNode* node )
642{
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800645}
646
647
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800648XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
649{
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 if ( _lastChild ) {
651 TIXMLASSERT( _firstChild );
652 TIXMLASSERT( _lastChild->_next == 0 );
653 _lastChild->_next = addThis;
654 addThis->_prev = _lastChild;
655 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
659 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 TIXMLASSERT( _firstChild == 0 );
661 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800662
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 addThis->_prev = 0;
664 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800667 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800669}
670
671
Lee Thomason1ff38e02012-02-14 18:18:16 -0800672XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
673{
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 if ( _firstChild ) {
675 TIXMLASSERT( _lastChild );
676 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 _firstChild->_prev = addThis;
679 addThis->_next = _firstChild;
680 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 }
684 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 TIXMLASSERT( _lastChild == 0 );
686 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 addThis->_prev = 0;
689 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800692 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800694}
695
696
697XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
698{
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 TIXMLASSERT( afterThis->_parent == this );
700 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 return 0;
702 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800703
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 // The last node or the only node.
706 return InsertEndChild( addThis );
707 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 addThis->_prev = afterThis;
709 addThis->_next = afterThis->_next;
710 afterThis->_next->_prev = addThis;
711 afterThis->_next = addThis;
712 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800713 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800715}
716
717
718
719
Lee Thomason56bdd022012-02-09 18:16:58 -0800720const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800721{
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 XMLElement* element = node->ToElement();
724 if ( element ) {
725 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
726 return element;
727 }
728 }
729 }
730 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800731}
732
733
Lee Thomason56bdd022012-02-09 18:16:58 -0800734const XMLElement* XMLNode::LastChildElement( const char* value ) const
735{
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 XMLElement* element = node->ToElement();
738 if ( element ) {
739 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
740 return element;
741 }
742 }
743 }
744 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800745}
746
747
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800748const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
749{
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 if ( element->ToElement()
752 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
753 return element->ToElement();
754 }
755 }
756 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800757}
758
759
760const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
761{
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 if ( element->ToElement()
764 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
765 return element->ToElement();
766 }
767 }
768 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800769}
770
771
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800772char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800773{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 // This is a recursive method, but thinking about it "at the current level"
775 // it is a pretty simple flat list:
776 // <foo/>
777 // <!-- comment -->
778 //
779 // With a special case:
780 // <foo>
781 // </foo>
782 // <!-- comment -->
783 //
784 // Where the closing element (/foo) *must* be the next thing after the opening
785 // element, and the names must match. BUT the tricky bit is that the closing
786 // element will be read by the child.
787 //
788 // 'endTag' is the end tag for this node, it is returned by a call to a child.
789 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800790
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 while( p && *p ) {
792 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800793
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 if ( p == 0 || node == 0 ) {
796 break;
797 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800798
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 StrPair endTag;
800 p = node->ParseDeep( p, &endTag );
801 if ( !p ) {
802 DELETE_NODE( node );
803 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700804 if ( !_document->Error() ) {
805 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
807 break;
808 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800809
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 // We read the end tag. Return it to the parent.
811 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
812 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700813 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800815 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 DELETE_NODE( node );
817 return p;
818 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800819
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 // Handle an end tag returned to this level.
821 // And handle a bunch of annoying errors.
822 XMLElement* ele = node->ToElement();
823 if ( ele ) {
824 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 p = 0;
827 }
828 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 p = 0;
831 }
832 else if ( !endTag.Empty() ) {
833 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
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 }
838 }
839 if ( p == 0 ) {
840 DELETE_NODE( node );
841 node = 0;
842 }
843 if ( node ) {
844 this->InsertEndChild( node );
845 }
846 }
847 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800848}
849
Lee Thomason5492a1c2012-01-23 15:32:10 -0800850// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800851char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800852{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 const char* start = p;
854 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 return p;
860 }
861 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
863 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 flags |= StrPair::COLLAPSE_WHITESPACE;
865 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700866
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700869 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
871 if ( p && *p ) {
872 return p-1;
873 }
874 }
875 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876}
877
878
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800879XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
885 text->SetCData( this->CData() );
886 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800887}
888
889
890bool XMLText::ShallowEqual( const XMLNode* compare ) const
891{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800893}
894
895
Lee Thomason56bdd022012-02-09 18:16:58 -0800896bool XMLText::Accept( XMLVisitor* visitor ) const
897{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800899}
900
901
Lee Thomason3f57d272012-01-11 15:30:03 -0800902// --------- XMLComment ---------- //
903
Lee Thomasone4422302012-01-20 17:59:50 -0800904XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800905{
906}
907
908
Lee Thomasonce0763e2012-01-11 15:43:54 -0800909XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800910{
Lee Thomason3f57d272012-01-11 15:30:03 -0800911}
912
913
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800914char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 // Comment parses as text.
917 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700918 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700920 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 }
922 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800923}
924
925
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800926XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
927{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 }
931 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
932 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800933}
934
935
936bool XMLComment::ShallowEqual( const XMLNode* compare ) const
937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800939}
940
941
Lee Thomason751da522012-02-10 08:50:51 -0800942bool XMLComment::Accept( XMLVisitor* visitor ) const
943{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800945}
Lee Thomason56bdd022012-02-09 18:16:58 -0800946
947
Lee Thomason50f97b22012-02-11 16:33:40 -0800948// --------- XMLDeclaration ---------- //
949
950XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
951{
952}
953
954
955XMLDeclaration::~XMLDeclaration()
956{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800958}
959
960
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800961char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 // Declaration parses as text.
964 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700965 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800970}
971
972
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
974{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700976 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 }
978 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
979 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800980}
981
982
983bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800986}
987
988
989
Lee Thomason50f97b22012-02-11 16:33:40 -0800990bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800993}
994
995// --------- XMLUnknown ---------- //
996
997XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
998{
999}
1000
1001
1002XMLUnknown::~XMLUnknown()
1003{
1004}
1005
1006
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001007char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 // Unknown parses as text.
1010 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001011
Lee Thomason624d43f2012-10-12 10:58:48 -07001012 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001014 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 }
1016 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001020XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001023 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 }
1025 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1026 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001027}
1028
1029
1030bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001033}
1034
1035
Lee Thomason50f97b22012-02-11 16:33:40 -08001036bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1037{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001039}
1040
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001041// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001042char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001043{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !p || !*p ) {
1047 return 0;
1048 }
Lee Thomason22aead12012-01-23 13:29:35 -08001049
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 // Skip white space before =
1051 p = XMLUtil::SkipWhiteSpace( p );
1052 if ( !p || *p != '=' ) {
1053 return 0;
1054 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001055
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 ++p; // move up to opening quote
1057 p = XMLUtil::SkipWhiteSpace( p );
1058 if ( *p != '\"' && *p != '\'' ) {
1059 return 0;
1060 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001061
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 char endTag[2] = { *p, 0 };
1063 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001064
Lee Thomason624d43f2012-10-12 10:58:48 -07001065 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001067}
1068
1069
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001070void XMLAttribute::SetName( const char* n )
1071{
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001073}
1074
1075
Lee Thomason2fa81722012-11-09 12:37:46 -08001076XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 if ( XMLUtil::ToInt( Value(), value )) {
1079 return XML_NO_ERROR;
1080 }
1081 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001082}
1083
1084
Lee Thomason2fa81722012-11-09 12:37:46 -08001085XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001086{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 if ( XMLUtil::ToUnsigned( Value(), value )) {
1088 return XML_NO_ERROR;
1089 }
1090 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001091}
1092
1093
Lee Thomason2fa81722012-11-09 12:37:46 -08001094XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 if ( XMLUtil::ToBool( Value(), value )) {
1097 return XML_NO_ERROR;
1098 }
1099 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001100}
1101
1102
Lee Thomason2fa81722012-11-09 12:37:46 -08001103XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001104{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 if ( XMLUtil::ToFloat( Value(), value )) {
1106 return XML_NO_ERROR;
1107 }
1108 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToDouble( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
1121void XMLAttribute::SetAttribute( const char* v )
1122{
Lee Thomason624d43f2012-10-12 10:58:48 -07001123 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001124}
1125
1126
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127void XMLAttribute::SetAttribute( int v )
1128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 char buf[BUF_SIZE];
1130 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001132}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001133
1134
1135void XMLAttribute::SetAttribute( unsigned v )
1136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 char buf[BUF_SIZE];
1138 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001140}
1141
1142
1143void XMLAttribute::SetAttribute( bool 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 Thomason1a1d4a72012-02-15 09:09:25 -08001148}
1149
1150void XMLAttribute::SetAttribute( double v )
1151{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 char buf[BUF_SIZE];
1153 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001154 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001155}
1156
1157void XMLAttribute::SetAttribute( float v )
1158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 char buf[BUF_SIZE];
1160 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001162}
1163
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001164
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001165// --------- XMLElement ---------- //
1166XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _closingType( 0 ),
1168 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001169{
1170}
1171
1172
1173XMLElement::~XMLElement()
1174{
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 while( _rootAttribute ) {
1176 XMLAttribute* next = _rootAttribute->_next;
1177 DELETE_ATTRIBUTE( _rootAttribute );
1178 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001180}
1181
1182
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001183XMLAttribute* XMLElement::FindAttribute( const char* name )
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1188 return a;
1189 }
1190 }
1191 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001192}
1193
1194
1195const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001198 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1200 return a;
1201 }
1202 }
1203 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001204}
1205
1206
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001207const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 const XMLAttribute* a = FindAttribute( name );
1210 if ( !a ) {
1211 return 0;
1212 }
1213 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1214 return a->Value();
1215 }
1216 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001217}
1218
1219
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001220const char* XMLElement::GetText() const
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( FirstChild() && FirstChild()->ToText() ) {
1223 return FirstChild()->ToText()->Value();
1224 }
1225 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001226}
1227
1228
MortenMacFly4ee49f12013-01-14 20:03:14 +01001229XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001230{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 if ( FirstChild() && FirstChild()->ToText() ) {
1232 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001233 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 return XML_SUCCESS;
1235 }
1236 return XML_CAN_NOT_CONVERT_TEXT;
1237 }
1238 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001239}
1240
1241
MortenMacFly4ee49f12013-01-14 20:03:14 +01001242XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 if ( FirstChild() && FirstChild()->ToText() ) {
1245 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001246 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 return XML_SUCCESS;
1248 }
1249 return XML_CAN_NOT_CONVERT_TEXT;
1250 }
1251 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001252}
1253
1254
MortenMacFly4ee49f12013-01-14 20:03:14 +01001255XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 if ( FirstChild() && FirstChild()->ToText() ) {
1258 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001259 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 return XML_SUCCESS;
1261 }
1262 return XML_CAN_NOT_CONVERT_TEXT;
1263 }
1264 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001265}
1266
1267
MortenMacFly4ee49f12013-01-14 20:03:14 +01001268XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 if ( FirstChild() && FirstChild()->ToText() ) {
1271 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001272 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 return XML_SUCCESS;
1274 }
1275 return XML_CAN_NOT_CONVERT_TEXT;
1276 }
1277 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001278}
1279
1280
MortenMacFly4ee49f12013-01-14 20:03:14 +01001281XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 if ( FirstChild() && FirstChild()->ToText() ) {
1284 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001285 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 return XML_SUCCESS;
1287 }
1288 return XML_CAN_NOT_CONVERT_TEXT;
1289 }
1290 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001291}
1292
1293
1294
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001295XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 XMLAttribute* last = 0;
1298 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001299 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1303 break;
1304 }
1305 }
1306 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001307 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1308 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001310 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 }
1312 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001316 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 }
1318 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001319}
1320
1321
U-Stream\Leeae25a442012-02-17 17:48:16 -08001322void XMLElement::DeleteAttribute( const char* name )
1323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1327 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 }
1330 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001331 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 }
1333 DELETE_ATTRIBUTE( a );
1334 break;
1335 }
1336 prev = a;
1337 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001338}
1339
1340
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001341char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 const char* start = p;
1344 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001345
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 // Read the attributes.
1347 while( p ) {
1348 p = XMLUtil::SkipWhiteSpace( p );
1349 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001350 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 return 0;
1352 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001355 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1357 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001358 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001359
Lee Thomason624d43f2012-10-12 10:58:48 -07001360 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 if ( !p || Attribute( attrib->Name() ) ) {
1362 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 return 0;
1365 }
1366 // There is a minor bug here: if the attribute in the source xml
1367 // document is duplicated, it will not be detected and the
1368 // attribute will be doubly added. However, tracking the 'prevAttribute'
1369 // avoids re-scanning the attribute list. Preferring performance for
1370 // now, may reconsider in the future.
1371 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 }
1374 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 }
1377 prevAttribute = attrib;
1378 }
1379 // end of the tag
1380 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001381 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 return p+2; // done; sealed element.
1383 }
1384 // end of the tag
1385 else if ( *p == '>' ) {
1386 ++p;
1387 break;
1388 }
1389 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001390 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 return 0;
1392 }
1393 }
1394 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001395}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001396
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001397
Lee Thomason67d61312012-01-24 16:01:51 -08001398//
1399// <ele></ele>
1400// <ele>foo<b>bar</b></ele>
1401//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001402char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 // Read the element name.
1405 p = XMLUtil::SkipWhiteSpace( p );
1406 if ( !p ) {
1407 return 0;
1408 }
Lee Thomason67d61312012-01-24 16:01:51 -08001409
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 // The closing element is the </element> form. It is
1411 // parsed just like a regular element then deleted from
1412 // the DOM.
1413 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 ++p;
1416 }
Lee Thomason67d61312012-01-24 16:01:51 -08001417
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 p = _value.ParseName( p );
1419 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 return 0;
1421 }
Lee Thomason67d61312012-01-24 16:01:51 -08001422
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 return p;
1426 }
Lee Thomason67d61312012-01-24 16:01:51 -08001427
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 p = XMLNode::ParseDeep( p, strPair );
1429 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001430}
1431
1432
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001433
1434XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
1439 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1440 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1441 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1442 }
1443 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001444}
1445
1446
1447bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 const XMLElement* other = compare->ToElement();
1450 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001451
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 const XMLAttribute* a=FirstAttribute();
1453 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001454
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 while ( a && b ) {
1456 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1457 return false;
1458 }
1459 a = a->Next();
1460 b = b->Next();
1461 }
1462 if ( a || b ) {
1463 // different count
1464 return false;
1465 }
1466 return true;
1467 }
1468 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001469}
1470
1471
Lee Thomason751da522012-02-10 08:50:51 -08001472bool XMLElement::Accept( XMLVisitor* visitor ) const
1473{
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1476 if ( !node->Accept( visitor ) ) {
1477 break;
1478 }
1479 }
1480 }
1481 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001482}
Lee Thomason56bdd022012-02-09 18:16:58 -08001483
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001484
Lee Thomason3f57d272012-01-11 15:30:03 -08001485// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001486XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _writeBOM( false ),
1489 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001490 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 _whitespace( whitespace ),
1492 _errorStr1( 0 ),
1493 _errorStr2( 0 ),
1494 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001495{
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001497}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001498
1499
Lee Thomason3f57d272012-01-11 15:30:03 -08001500XMLDocument::~XMLDocument()
1501{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001504
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001505#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001506 _textPool.Trace( "text" );
1507 _elementPool.Trace( "element" );
1508 _commentPool.Trace( "comment" );
1509 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001510#endif
1511
Lee Thomason5b0a6772012-11-19 13:54:42 -08001512#ifdef DEBUG
1513 if ( Error() == false ) {
1514 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1515 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1516 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1517 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1518 }
1519#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001520}
1521
1522
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001523void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001524{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001525 DeleteChildren();
1526
Lee Thomason624d43f2012-10-12 10:58:48 -07001527 _errorID = XML_NO_ERROR;
1528 _errorStr1 = 0;
1529 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001530
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 delete [] _charBuffer;
1532 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001533}
1534
Lee Thomason3f57d272012-01-11 15:30:03 -08001535
Lee Thomason2c85a712012-01-31 08:24:24 -08001536XMLElement* XMLDocument::NewElement( const char* name )
1537{
Lee Thomason624d43f2012-10-12 10:58:48 -07001538 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1539 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 ele->SetName( name );
1541 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001542}
1543
1544
Lee Thomason1ff38e02012-02-14 18:18:16 -08001545XMLComment* XMLDocument::NewComment( const char* str )
1546{
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1548 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 comment->SetValue( str );
1550 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001551}
1552
1553
1554XMLText* XMLDocument::NewText( const char* str )
1555{
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1557 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 text->SetValue( str );
1559 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001560}
1561
1562
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1564{
Lee Thomason624d43f2012-10-12 10:58:48 -07001565 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1566 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1568 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569}
1570
1571
1572XMLUnknown* XMLDocument::NewUnknown( const char* str )
1573{
Lee Thomason624d43f2012-10-12 10:58:48 -07001574 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1575 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 unk->SetValue( str );
1577 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578}
1579
1580
Lee Thomason2fa81722012-11-09 12:37:46 -08001581XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001582{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001583 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001585
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1587 errno_t err = fopen_s(&fp, filename, "rb" );
1588 if ( !fp || err) {
1589#else
1590 fp = fopen( filename, "rb" );
1591 if ( !fp) {
1592#endif
1593 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 }
1596 LoadFile( fp );
1597 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001599}
1600
1601
Lee Thomason2fa81722012-11-09 12:37:46 -08001602XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001603{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001604 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001605
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 fseek( fp, 0, SEEK_END );
1607 size_t size = ftell( fp );
1608 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001609
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001611 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001614
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 _charBuffer = new char[size+1];
1616 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 if ( read != size ) {
1618 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001621
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001623
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 if ( !p || !*p ) {
1628 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001631
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1633 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001634}
1635
1636
Lee Thomason2fa81722012-11-09 12:37:46 -08001637XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001638{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 FILE* fp = 0;
1640#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1641 errno_t err = fopen_s(&fp, filename, "w" );
1642 if ( !fp || err) {
1643#else
1644 fp = fopen( filename, "w" );
1645 if ( !fp) {
1646#endif
1647 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 }
1650 SaveFile(fp, compact);
1651 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001653}
1654
1655
Lee Thomason2fa81722012-11-09 12:37:46 -08001656XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001657{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 XMLPrinter stream( fp, compact );
1659 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001660 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001661}
1662
Lee Thomason1ff38e02012-02-14 18:18:16 -08001663
Lee Thomason2fa81722012-11-09 12:37:46 -08001664XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001665{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001666 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001667 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001668
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 if ( !p || !*p ) {
1670 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 }
1673 if ( len == (size_t)(-1) ) {
1674 len = strlen( p );
1675 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 _charBuffer = new char[ len+1 ];
1677 memcpy( _charBuffer, p, len );
1678 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001679
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 if ( !p || !*p ) {
1683 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001686
Thomas Roß1470edc2013-05-10 15:44:12 +02001687 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001688 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001690}
1691
1692
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001693void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001694{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 XMLPrinter stdStreamer( stdout );
1696 if ( !streamer ) {
1697 streamer = &stdStreamer;
1698 }
1699 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001700}
1701
1702
Lee Thomason2fa81722012-11-09 12:37:46 -08001703void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001704{
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 _errorID = error;
1706 _errorStr1 = str1;
1707 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001708}
1709
Lee Thomason5cae8972012-01-24 18:03:07 -08001710
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001711void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001712{
Lee Thomason624d43f2012-10-12 10:58:48 -07001713 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 static const int LEN = 20;
1715 char buf1[LEN] = { 0 };
1716 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001717
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 if ( _errorStr1 ) {
1719 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 if ( _errorStr2 ) {
1722 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001724
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728}
1729
1730
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001731XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 _elementJustOpened( false ),
1733 _firstElement( true ),
1734 _fp( file ),
1735 _depth( 0 ),
1736 _textDepth( -1 ),
1737 _processEntities( true ),
1738 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001739{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 _entityFlag[i] = false;
1742 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 }
1744 for( int i=0; i<NUM_ENTITIES; ++i ) {
1745 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1746 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 }
1749 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 _restrictedEntityFlag[(int)'&'] = true;
1751 _restrictedEntityFlag[(int)'<'] = true;
1752 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1753 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001754}
1755
1756
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001757void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001758{
1759 va_list va;
1760 va_start( va, format );
1761
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 if ( _fp ) {
1763 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 }
1765 else {
1766 // This seems brutally complex. Haven't figured out a better
1767 // way on windows.
1768#ifdef _MSC_VER
1769 int len = -1;
1770 int expand = 1000;
1771 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 if ( len < 0 ) {
1774 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001775 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
1777 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 char* p = _buffer.PushArr( len ) - 1;
1779 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780#else
1781 int len = vsnprintf( 0, 0, format, va );
1782 // Close out and re-start the va-args
1783 va_end( va );
1784 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 vsnprintf( p, len+1, format, va );
1787#endif
1788 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001789 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001790}
1791
1792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001793void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 for( int i=0; i<depth; ++i ) {
1796 Print( " " );
1797 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001798}
1799
1800
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001801void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001802{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 // Look for runs of bytes between entities to print.
1804 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001806
Lee Thomason624d43f2012-10-12 10:58:48 -07001807 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 while ( *q ) {
1809 // Remember, char is sometimes signed. (How many times has that bitten me?)
1810 if ( *q > 0 && *q < ENTITY_RANGE ) {
1811 // Check for entities. If one is found, flush
1812 // the stream up until the entity, write the
1813 // entity, and keep looking.
1814 if ( flag[(unsigned)(*q)] ) {
1815 while ( p < q ) {
1816 Print( "%c", *p );
1817 ++p;
1818 }
1819 for( int i=0; i<NUM_ENTITIES; ++i ) {
1820 if ( entities[i].value == *q ) {
1821 Print( "&%s;", entities[i].pattern );
1822 break;
1823 }
1824 }
1825 ++p;
1826 }
1827 }
1828 ++q;
1829 }
1830 }
1831 // Flush the remaining string. This will be the entire
1832 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 Print( "%s", p );
1835 }
Lee Thomason857b8682012-01-25 17:50:25 -08001836}
1837
U-Stream\Leeae25a442012-02-17 17:48:16 -08001838
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001839void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001840{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1842 if ( writeBOM ) {
1843 Print( "%s", bom );
1844 }
1845 if ( writeDec ) {
1846 PushDeclaration( "xml version=\"1.0\"" );
1847 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001848}
1849
1850
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001851void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001852{
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 SealElement();
1855 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001857
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001862
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 _elementJustOpened = true;
1865 _firstElement = false;
1866 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001867}
1868
1869
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001870void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001871{
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 Print( " %s=\"", name );
1874 PrintString( value, false );
1875 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001876}
1877
1878
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001879void XMLPrinter::PushAttribute( const char* name, int v )
1880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 char buf[BUF_SIZE];
1882 XMLUtil::ToStr( v, buf, BUF_SIZE );
1883 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001884}
1885
1886
1887void XMLPrinter::PushAttribute( const char* name, unsigned v )
1888{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 char buf[BUF_SIZE];
1890 XMLUtil::ToStr( v, buf, BUF_SIZE );
1891 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001892}
1893
1894
1895void XMLPrinter::PushAttribute( const char* name, bool v )
1896{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 char buf[BUF_SIZE];
1898 XMLUtil::ToStr( v, buf, BUF_SIZE );
1899 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001900}
1901
1902
1903void XMLPrinter::PushAttribute( const char* name, double v )
1904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 char buf[BUF_SIZE];
1906 XMLUtil::ToStr( v, buf, BUF_SIZE );
1907 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001908}
1909
1910
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001911void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001912{
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 --_depth;
1914 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001915
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 Print( "/>" );
1918 }
1919 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 Print( "</%s>", name );
1925 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001926
Lee Thomason624d43f2012-10-12 10:58:48 -07001927 if ( _textDepth == _depth ) {
1928 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 Print( "\n" );
1932 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001934}
1935
1936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001938{
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001941}
1942
1943
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001944void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001945{
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001947
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 SealElement();
1950 }
1951 if ( cdata ) {
1952 Print( "<![CDATA[" );
1953 Print( "%s", text );
1954 Print( "]]>" );
1955 }
1956 else {
1957 PrintString( text, true );
1958 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001959}
1960
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001961void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 char buf[BUF_SIZE];
1964 XMLUtil::ToStr( value, buf, BUF_SIZE );
1965 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001966}
1967
1968
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001969void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 char buf[BUF_SIZE];
1972 XMLUtil::ToStr( value, buf, BUF_SIZE );
1973 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001974}
1975
1976
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001977void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 char buf[BUF_SIZE];
1980 XMLUtil::ToStr( value, buf, BUF_SIZE );
1981 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001982}
1983
1984
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001985void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 char buf[BUF_SIZE];
1988 XMLUtil::ToStr( value, buf, BUF_SIZE );
1989 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001990}
1991
1992
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001993void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 char buf[BUF_SIZE];
1996 XMLUtil::ToStr( value, buf, BUF_SIZE );
1997 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001998}
1999
Lee Thomason5cae8972012-01-24 18:03:07 -08002000
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002001void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002002{
Lee Thomason624d43f2012-10-12 10:58:48 -07002003 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 SealElement();
2005 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002012}
Lee Thomason751da522012-02-10 08:50:51 -08002013
2014
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002015void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002016{
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 SealElement();
2019 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _textDepth < 0 && !_firstElement && !_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 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002026}
2027
2028
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002029void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002030{
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 SealElement();
2033 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002038 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002044{
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 if ( doc.HasBOM() ) {
2047 PushHeader( true, false );
2048 }
2049 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002050}
2051
2052
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002053bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002054{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 OpenElement( element.Name() );
2056 while ( attribute ) {
2057 PushAttribute( attribute->Name(), attribute->Value() );
2058 attribute = attribute->Next();
2059 }
2060 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002061}
2062
2063
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002064bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 CloseElement();
2067 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002068}
2069
2070
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002071bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 PushText( text.Value(), text.CData() );
2074 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002075}
2076
2077
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002078bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 PushComment( comment.Value() );
2081 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002082}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 PushDeclaration( declaration.Value() );
2087 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002088}
2089
2090
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002091bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002092{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 PushUnknown( unknown.Value() );
2094 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002095}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002096
Lee Thomason685b8952012-11-12 13:00:06 -08002097} // namespace tinyxml2
2098