blob: 647901b702dd40afa53f8894e468bd9452635cd8 [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
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 while( *p && (
140 XMLUtil::IsAlphaNum( (unsigned char) *p )
141 || *p == '_'
142 || *p == ':'
143 || (*p == '-' && p>start ) // can be in a name, but not lead it.
144 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
145 ++p;
146 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800147
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700148 if ( p > start ) {
149 Set( start, p, 0 );
150 return p;
151 }
152 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800153}
154
155
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700156void StrPair::CollapseWhitespace()
157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700158 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700159 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700160
Lee Thomason120b3a62012-10-12 10:06:59 -0700161 if ( _start && *_start ) {
162 char* p = _start; // the read pointer
163 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700165 while( *p ) {
166 if ( XMLUtil::IsWhiteSpace( *p )) {
167 p = XMLUtil::SkipWhiteSpace( p );
168 if ( *p == 0 ) {
169 break; // don't write to q; this trims the trailing space.
170 }
171 *q = ' ';
172 ++q;
173 }
174 *q = *p;
175 ++q;
176 ++p;
177 }
178 *q = 0;
179 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700180}
181
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800182
Lee Thomasone4422302012-01-20 17:59:50 -0800183const char* StrPair::GetStr()
184{
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 if ( _flags & NEEDS_FLUSH ) {
186 *_end = 0;
187 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800188
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags ) {
190 char* p = _start; // the read pointer
191 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 while( p < _end ) {
194 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 // CR-LF pair becomes LF
196 // CR alone becomes LF
197 // LF-CR becomes LF
198 if ( *(p+1) == LF ) {
199 p += 2;
200 }
201 else {
202 ++p;
203 }
204 *q++ = LF;
205 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700206 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700207 if ( *(p+1) == CR ) {
208 p += 2;
209 }
210 else {
211 ++p;
212 }
213 *q++ = LF;
214 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700215 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 // Entities handled by tinyXML2:
217 // - special entities in the entity table [in/out]
218 // - numeric character reference [in]
219 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800220
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 if ( *(p+1) == '#' ) {
222 char buf[10] = { 0 };
223 int len;
224 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
225 for( int i=0; i<len; ++i ) {
226 *q++ = buf[i];
227 }
228 TIXMLASSERT( q <= p );
229 }
230 else {
231 int i=0;
232 for(; i<NUM_ENTITIES; ++i ) {
233 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
234 && *(p+entities[i].length+1) == ';' ) {
235 // Found an entity convert;
236 *q = entities[i].value;
237 ++q;
238 p += entities[i].length + 2;
239 break;
240 }
241 }
242 if ( i == NUM_ENTITIES ) {
243 // fixme: treat as error?
244 ++p;
245 ++q;
246 }
247 }
248 }
249 else {
250 *q = *p;
251 ++p;
252 ++q;
253 }
254 }
255 *q = 0;
256 }
257 // The loop below has plenty going on, and this
258 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 CollapseWhitespace();
261 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700262 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700263 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800265}
266
Lee Thomason2c85a712012-01-31 08:24:24 -0800267
Lee Thomasone4422302012-01-20 17:59:50 -0800268
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800269
Lee Thomason56bdd022012-02-09 18:16:58 -0800270// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800271
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800272const char* XMLUtil::ReadBOM( const char* p, bool* bom )
273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700274 *bom = false;
275 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
276 // Check for BOM:
277 if ( *(pu+0) == TIXML_UTF_LEAD_0
278 && *(pu+1) == TIXML_UTF_LEAD_1
279 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
280 *bom = true;
281 p += 3;
282 }
283 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800284}
285
286
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700289 const unsigned long BYTE_MASK = 0xBF;
290 const unsigned long BYTE_MARK = 0x80;
291 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800292
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if (input < 0x80) {
294 *length = 1;
295 }
296 else if ( input < 0x800 ) {
297 *length = 2;
298 }
299 else if ( input < 0x10000 ) {
300 *length = 3;
301 }
302 else if ( input < 0x200000 ) {
303 *length = 4;
304 }
305 else {
306 *length = 0; // This code won't covert this correctly anyway.
307 return;
308 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800309
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800311
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700312 // Scary scary fall throughs.
313 switch (*length) {
314 case 4:
315 --output;
316 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
317 input >>= 6;
318 case 3:
319 --output;
320 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
321 input >>= 6;
322 case 2:
323 --output;
324 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
325 input >>= 6;
326 case 1:
327 --output;
328 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100329 default:
330 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332}
333
334
335const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 // Presume an entity, and pull it out.
338 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+1) == '#' && *(p+2) ) {
341 unsigned long ucs = 0;
342 ptrdiff_t delta = 0;
343 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700345 if ( *(p+2) == 'x' ) {
346 // Hexadecimal.
347 if ( !*(p+3) ) {
348 return 0;
349 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 const char* q = p+3;
352 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 if ( !q || !*q ) {
355 return 0;
356 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 delta = q-p;
359 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800360
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 while ( *q != 'x' ) {
362 if ( *q >= '0' && *q <= '9' ) {
363 ucs += mult * (*q - '0');
364 }
365 else if ( *q >= 'a' && *q <= 'f' ) {
366 ucs += mult * (*q - 'a' + 10);
367 }
368 else if ( *q >= 'A' && *q <= 'F' ) {
369 ucs += mult * (*q - 'A' + 10 );
370 }
371 else {
372 return 0;
373 }
374 mult *= 16;
375 --q;
376 }
377 }
378 else {
379 // Decimal.
380 if ( !*(p+2) ) {
381 return 0;
382 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800383
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 const char* q = p+2;
385 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 if ( !q || !*q ) {
388 return 0;
389 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800390
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 delta = q-p;
392 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800393
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 while ( *q != '#' ) {
395 if ( *q >= '0' && *q <= '9' ) {
396 ucs += mult * (*q - '0');
397 }
398 else {
399 return 0;
400 }
401 mult *= 10;
402 --q;
403 }
404 }
405 // convert the UCS to UTF-8
406 ConvertUTF32ToUTF8( ucs, value, length );
407 return p + delta + 1;
408 }
409 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800411
412
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700413void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700415 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700416}
417
418
419void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
442
443bool XMLUtil::ToInt( const char* str, int* value )
444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
446 return true;
447 }
448 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
454 return true;
455 }
456 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700457}
458
459bool XMLUtil::ToBool( const char* str, bool* value )
460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 int ival = 0;
462 if ( ToInt( str, &ival )) {
463 *value = (ival==0) ? false : true;
464 return true;
465 }
466 if ( StringEqual( str, "true" ) ) {
467 *value = true;
468 return true;
469 }
470 else if ( StringEqual( str, "false" ) ) {
471 *value = false;
472 return true;
473 }
474 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700475}
476
477
478bool XMLUtil::ToFloat( const char* str, float* value )
479{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486bool XMLUtil::ToDouble( const char* str, double* value )
487{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
489 return true;
490 }
491 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700492}
493
494
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700495char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 XMLNode* returnNode = 0;
498 char* start = p;
499 p = XMLUtil::SkipWhiteSpace( p );
500 if( !p || !*p ) {
501 return p;
502 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800503
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 // What is this thing?
505 // - Elements start with a letter or underscore, but xml is reserved.
506 // - Comments: <!--
507 // - Decleration: <?
508 // - Everthing else is unknown to tinyxml.
509 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800510
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700511 static const char* xmlHeader = { "<?" };
512 static const char* commentHeader = { "<!--" };
513 static const char* dtdHeader = { "<!" };
514 static const char* cdataHeader = { "<![CDATA[" };
515 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800516
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 static const int xmlHeaderLen = 2;
518 static const int commentHeaderLen = 4;
519 static const int dtdHeaderLen = 2;
520 static const int cdataHeaderLen = 9;
521 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800522
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800524#pragma warning ( push )
525#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
528 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800530#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800531#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
534 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 p += xmlHeaderLen;
536 }
537 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLComment( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += commentHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += cdataHeaderLen;
547 text->SetCData( true );
548 }
549 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
551 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += dtdHeaderLen;
553 }
554 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_elementPool.Alloc()) XMLElement( this );
556 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p += elementHeaderLen;
558 }
559 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_textPool.Alloc()) XMLText( this );
561 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p = start; // Back it up, all the text counts.
563 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800564
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 *node = returnNode;
566 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800567}
568
569
Lee Thomason751da522012-02-10 08:50:51 -0800570bool XMLDocument::Accept( XMLVisitor* visitor ) const
571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 if ( visitor->VisitEnter( *this ) ) {
573 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
574 if ( !node->Accept( visitor ) ) {
575 break;
576 }
577 }
578 }
579 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800580}
Lee Thomason56bdd022012-02-09 18:16:58 -0800581
582
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800583// --------- XMLNode ----------- //
584
585XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700586 _document( doc ),
587 _parent( 0 ),
588 _firstChild( 0 ), _lastChild( 0 ),
589 _prev( 0 ), _next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800590{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800591}
592
593
594XMLNode::~XMLNode()
595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700597 if ( _parent ) {
598 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600}
601
602
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 ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001047char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001048{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001050 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 if ( !p || !*p ) {
1052 return 0;
1053 }
Lee Thomason22aead12012-01-23 13:29:35 -08001054
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 // Skip white space before =
1056 p = XMLUtil::SkipWhiteSpace( p );
1057 if ( !p || *p != '=' ) {
1058 return 0;
1059 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001060
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 ++p; // move up to opening quote
1062 p = XMLUtil::SkipWhiteSpace( p );
1063 if ( *p != '\"' && *p != '\'' ) {
1064 return 0;
1065 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001066
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 char endTag[2] = { *p, 0 };
1068 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001069
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001072}
1073
1074
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001075void XMLAttribute::SetName( const char* n )
1076{
Lee Thomason624d43f2012-10-12 10:58:48 -07001077 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001078}
1079
1080
Lee Thomason2fa81722012-11-09 12:37:46 -08001081XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 if ( XMLUtil::ToInt( Value(), value )) {
1084 return XML_NO_ERROR;
1085 }
1086 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001087}
1088
1089
Lee Thomason2fa81722012-11-09 12:37:46 -08001090XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 if ( XMLUtil::ToUnsigned( Value(), value )) {
1093 return XML_NO_ERROR;
1094 }
1095 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001096}
1097
1098
Lee Thomason2fa81722012-11-09 12:37:46 -08001099XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 if ( XMLUtil::ToBool( Value(), value )) {
1102 return XML_NO_ERROR;
1103 }
1104 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001105}
1106
1107
Lee Thomason2fa81722012-11-09 12:37:46 -08001108XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 if ( XMLUtil::ToFloat( Value(), value )) {
1111 return XML_NO_ERROR;
1112 }
1113 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001114}
1115
1116
Lee Thomason2fa81722012-11-09 12:37:46 -08001117XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 if ( XMLUtil::ToDouble( Value(), value )) {
1120 return XML_NO_ERROR;
1121 }
1122 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001123}
1124
1125
1126void XMLAttribute::SetAttribute( const char* v )
1127{
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001129}
1130
1131
Lee Thomason1ff38e02012-02-14 18:18:16 -08001132void XMLAttribute::SetAttribute( int v )
1133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 char buf[BUF_SIZE];
1135 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001136 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001137}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001138
1139
1140void XMLAttribute::SetAttribute( unsigned v )
1141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 char buf[BUF_SIZE];
1143 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001144 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001145}
1146
1147
1148void XMLAttribute::SetAttribute( bool v )
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 char buf[BUF_SIZE];
1151 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001153}
1154
1155void XMLAttribute::SetAttribute( double v )
1156{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 char buf[BUF_SIZE];
1158 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001160}
1161
1162void XMLAttribute::SetAttribute( float v )
1163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 char buf[BUF_SIZE];
1165 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001167}
1168
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001169
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001170// --------- XMLElement ---------- //
1171XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001172 _closingType( 0 ),
1173 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001174{
1175}
1176
1177
1178XMLElement::~XMLElement()
1179{
Lee Thomason624d43f2012-10-12 10:58:48 -07001180 while( _rootAttribute ) {
1181 XMLAttribute* next = _rootAttribute->_next;
1182 DELETE_ATTRIBUTE( _rootAttribute );
1183 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001185}
1186
1187
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001188XMLAttribute* XMLElement::FindAttribute( const char* name )
1189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1193 return a;
1194 }
1195 }
1196 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001197}
1198
1199
1200const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1205 return a;
1206 }
1207 }
1208 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001209}
1210
1211
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001212const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 const XMLAttribute* a = FindAttribute( name );
1215 if ( !a ) {
1216 return 0;
1217 }
1218 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1219 return a->Value();
1220 }
1221 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001222}
1223
1224
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001225const char* XMLElement::GetText() const
1226{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 if ( FirstChild() && FirstChild()->ToText() ) {
1228 return FirstChild()->ToText()->Value();
1229 }
1230 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001231}
1232
1233
MortenMacFly4ee49f12013-01-14 20:03:14 +01001234XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 if ( FirstChild() && FirstChild()->ToText() ) {
1237 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001238 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 return XML_SUCCESS;
1240 }
1241 return XML_CAN_NOT_CONVERT_TEXT;
1242 }
1243 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001244}
1245
1246
MortenMacFly4ee49f12013-01-14 20:03:14 +01001247XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 if ( FirstChild() && FirstChild()->ToText() ) {
1250 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001251 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 return XML_SUCCESS;
1253 }
1254 return XML_CAN_NOT_CONVERT_TEXT;
1255 }
1256 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001257}
1258
1259
MortenMacFly4ee49f12013-01-14 20:03:14 +01001260XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 if ( FirstChild() && FirstChild()->ToText() ) {
1263 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001264 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 return XML_SUCCESS;
1266 }
1267 return XML_CAN_NOT_CONVERT_TEXT;
1268 }
1269 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001270}
1271
1272
MortenMacFly4ee49f12013-01-14 20:03:14 +01001273XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( FirstChild() && FirstChild()->ToText() ) {
1276 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001277 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 return XML_SUCCESS;
1279 }
1280 return XML_CAN_NOT_CONVERT_TEXT;
1281 }
1282 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001283}
1284
1285
MortenMacFly4ee49f12013-01-14 20:03:14 +01001286XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 if ( FirstChild() && FirstChild()->ToText() ) {
1289 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001290 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 return XML_SUCCESS;
1292 }
1293 return XML_CAN_NOT_CONVERT_TEXT;
1294 }
1295 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001296}
1297
1298
1299
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001300XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1301{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 XMLAttribute* last = 0;
1303 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001304 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001306 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1308 break;
1309 }
1310 }
1311 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1313 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001315 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 }
1317 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001318 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 }
1320 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001321 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 }
1323 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001324}
1325
1326
U-Stream\Leeae25a442012-02-17 17:48:16 -08001327void XMLElement::DeleteAttribute( const char* name )
1328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001330 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1332 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001333 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 }
1335 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001336 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 }
1338 DELETE_ATTRIBUTE( a );
1339 break;
1340 }
1341 prev = a;
1342 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001343}
1344
1345
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001346char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 const char* start = p;
1349 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001350
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 // Read the attributes.
1352 while( p ) {
1353 p = XMLUtil::SkipWhiteSpace( p );
1354 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001355 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 return 0;
1357 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001358
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 // attribute.
1360 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001361 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1362 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001363 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001364
Lee Thomason624d43f2012-10-12 10:58:48 -07001365 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 if ( !p || Attribute( attrib->Name() ) ) {
1367 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001368 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 return 0;
1370 }
1371 // There is a minor bug here: if the attribute in the source xml
1372 // document is duplicated, it will not be detected and the
1373 // attribute will be doubly added. However, tracking the 'prevAttribute'
1374 // avoids re-scanning the attribute list. Preferring performance for
1375 // now, may reconsider in the future.
1376 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 }
1379 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001380 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 }
1382 prevAttribute = attrib;
1383 }
1384 // end of the tag
1385 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return p+2; // done; sealed element.
1388 }
1389 // end of the tag
1390 else if ( *p == '>' ) {
1391 ++p;
1392 break;
1393 }
1394 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 return 0;
1397 }
1398 }
1399 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001400}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001401
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001402
Lee Thomason67d61312012-01-24 16:01:51 -08001403//
1404// <ele></ele>
1405// <ele>foo<b>bar</b></ele>
1406//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001407char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 // Read the element name.
1410 p = XMLUtil::SkipWhiteSpace( p );
1411 if ( !p ) {
1412 return 0;
1413 }
Lee Thomason67d61312012-01-24 16:01:51 -08001414
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 // The closing element is the </element> form. It is
1416 // parsed just like a regular element then deleted from
1417 // the DOM.
1418 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 ++p;
1421 }
Lee Thomason67d61312012-01-24 16:01:51 -08001422
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 p = _value.ParseName( p );
1424 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 return 0;
1426 }
Lee Thomason67d61312012-01-24 16:01:51 -08001427
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 return p;
1431 }
Lee Thomason67d61312012-01-24 16:01:51 -08001432
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 p = XMLNode::ParseDeep( p, strPair );
1434 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001435}
1436
1437
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001438
1439XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 }
1444 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1445 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1446 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1447 }
1448 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001449}
1450
1451
1452bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 const XMLElement* other = compare->ToElement();
1455 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001456
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 const XMLAttribute* a=FirstAttribute();
1458 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001459
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 while ( a && b ) {
1461 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1462 return false;
1463 }
1464 a = a->Next();
1465 b = b->Next();
1466 }
1467 if ( a || b ) {
1468 // different count
1469 return false;
1470 }
1471 return true;
1472 }
1473 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001474}
1475
1476
Lee Thomason751da522012-02-10 08:50:51 -08001477bool XMLElement::Accept( XMLVisitor* visitor ) const
1478{
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1481 if ( !node->Accept( visitor ) ) {
1482 break;
1483 }
1484 }
1485 }
1486 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001487}
Lee Thomason56bdd022012-02-09 18:16:58 -08001488
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001489
Lee Thomason3f57d272012-01-11 15:30:03 -08001490// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001491XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _writeBOM( false ),
1494 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001495 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _whitespace( whitespace ),
1497 _errorStr1( 0 ),
1498 _errorStr2( 0 ),
1499 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001500{
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001502}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001503
1504
Lee Thomason3f57d272012-01-11 15:30:03 -08001505XMLDocument::~XMLDocument()
1506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001509
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001510#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 textPool.Trace( "text" );
1512 elementPool.Trace( "element" );
1513 commentPool.Trace( "comment" );
1514 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001515#endif
1516
Lee Thomason5b0a6772012-11-19 13:54:42 -08001517#ifdef DEBUG
1518 if ( Error() == false ) {
1519 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1520 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1521 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1522 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1523 }
1524#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001525}
1526
1527
Lee Thomason18d68bd2012-01-26 18:17:26 -08001528void XMLDocument::InitDocument()
1529{
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _errorID = XML_NO_ERROR;
1531 _errorStr1 = 0;
1532 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001533
Lee Thomason624d43f2012-10-12 10:58:48 -07001534 delete [] _charBuffer;
1535 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001536}
1537
Lee Thomason3f57d272012-01-11 15:30:03 -08001538
Lee Thomason2c85a712012-01-31 08:24:24 -08001539XMLElement* XMLDocument::NewElement( const char* name )
1540{
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1542 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 ele->SetName( name );
1544 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001545}
1546
1547
Lee Thomason1ff38e02012-02-14 18:18:16 -08001548XMLComment* XMLDocument::NewComment( const char* str )
1549{
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1551 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 comment->SetValue( str );
1553 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001554}
1555
1556
1557XMLText* XMLDocument::NewText( const char* str )
1558{
Lee Thomason624d43f2012-10-12 10:58:48 -07001559 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1560 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 text->SetValue( str );
1562 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001563}
1564
1565
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001566XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1567{
Lee Thomason624d43f2012-10-12 10:58:48 -07001568 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1569 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1571 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572}
1573
1574
1575XMLUnknown* XMLDocument::NewUnknown( const char* str )
1576{
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1578 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 unk->SetValue( str );
1580 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001581}
1582
1583
Lee Thomason2fa81722012-11-09 12:37:46 -08001584XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001585{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 DeleteChildren();
1587 InitDocument();
1588 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001589
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1591 errno_t err = fopen_s(&fp, filename, "rb" );
1592 if ( !fp || err) {
1593#else
1594 fp = fopen( filename, "rb" );
1595 if ( !fp) {
1596#endif
1597 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 }
1600 LoadFile( fp );
1601 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001602 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001603}
1604
1605
Lee Thomason2fa81722012-11-09 12:37:46 -08001606XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 DeleteChildren();
1609 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001610
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 fseek( fp, 0, SEEK_END );
1612 size_t size = ftell( fp );
1613 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001614
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 if ( size == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001618
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 _charBuffer = new char[size+1];
1620 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 if ( read != size ) {
1622 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001625
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001627
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001630 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 if ( !p || !*p ) {
1632 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001633 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001635
Lee Thomason624d43f2012-10-12 10:58:48 -07001636 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1637 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001638}
1639
1640
Lee Thomason2fa81722012-11-09 12:37:46 -08001641XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 FILE* fp = 0;
1644#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1645 errno_t err = fopen_s(&fp, filename, "w" );
1646 if ( !fp || err) {
1647#else
1648 fp = fopen( filename, "w" );
1649 if ( !fp) {
1650#endif
1651 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 }
1654 SaveFile(fp, compact);
1655 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001657}
1658
1659
Lee Thomason2fa81722012-11-09 12:37:46 -08001660XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001661{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 XMLPrinter stream( fp, compact );
1663 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001665}
1666
Lee Thomason1ff38e02012-02-14 18:18:16 -08001667
Lee Thomason2fa81722012-11-09 12:37:46 -08001668XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001669{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 DeleteChildren();
1671 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001672
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 if ( !p || !*p ) {
1674 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 }
1677 if ( len == (size_t)(-1) ) {
1678 len = strlen( p );
1679 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 _charBuffer = new char[ len+1 ];
1681 memcpy( _charBuffer, p, len );
1682 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001683
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 if ( !p || !*p ) {
1687 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001690
Lee Thomason624d43f2012-10-12 10:58:48 -07001691 ParseDeep( _charBuffer, 0 );
1692 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001693}
1694
1695
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001696void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001697{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 XMLPrinter stdStreamer( stdout );
1699 if ( !streamer ) {
1700 streamer = &stdStreamer;
1701 }
1702 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001703}
1704
1705
Lee Thomason2fa81722012-11-09 12:37:46 -08001706void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001707{
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 _errorID = error;
1709 _errorStr1 = str1;
1710 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001711}
1712
Lee Thomason5cae8972012-01-24 18:03:07 -08001713
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001714void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001715{
Lee Thomason624d43f2012-10-12 10:58:48 -07001716 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 static const int LEN = 20;
1718 char buf1[LEN] = { 0 };
1719 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001720
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 if ( _errorStr1 ) {
1722 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 if ( _errorStr2 ) {
1725 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731}
1732
1733
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001734XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 _elementJustOpened( false ),
1736 _firstElement( true ),
1737 _fp( file ),
1738 _depth( 0 ),
1739 _textDepth( -1 ),
1740 _processEntities( true ),
1741 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001742{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 _entityFlag[i] = false;
1745 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 }
1747 for( int i=0; i<NUM_ENTITIES; ++i ) {
1748 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1749 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 }
1752 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 _restrictedEntityFlag[(int)'&'] = true;
1754 _restrictedEntityFlag[(int)'<'] = true;
1755 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1756 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001757}
1758
1759
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001760void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001761{
1762 va_list va;
1763 va_start( va, format );
1764
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 if ( _fp ) {
1766 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 else {
1769 // This seems brutally complex. Haven't figured out a better
1770 // way on windows.
1771#ifdef _MSC_VER
1772 int len = -1;
1773 int expand = 1000;
1774 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 if ( len < 0 ) {
1777 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001778 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 char* p = _buffer.PushArr( len ) - 1;
1782 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783#else
1784 int len = vsnprintf( 0, 0, format, va );
1785 // Close out and re-start the va-args
1786 va_end( va );
1787 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 vsnprintf( p, len+1, format, va );
1790#endif
1791 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001792 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001793}
1794
1795
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001796void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001797{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 for( int i=0; i<depth; ++i ) {
1799 Print( " " );
1800 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001801}
1802
1803
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001804void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001805{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 // Look for runs of bytes between entities to print.
1807 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001809
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 while ( *q ) {
1812 // Remember, char is sometimes signed. (How many times has that bitten me?)
1813 if ( *q > 0 && *q < ENTITY_RANGE ) {
1814 // Check for entities. If one is found, flush
1815 // the stream up until the entity, write the
1816 // entity, and keep looking.
1817 if ( flag[(unsigned)(*q)] ) {
1818 while ( p < q ) {
1819 Print( "%c", *p );
1820 ++p;
1821 }
1822 for( int i=0; i<NUM_ENTITIES; ++i ) {
1823 if ( entities[i].value == *q ) {
1824 Print( "&%s;", entities[i].pattern );
1825 break;
1826 }
1827 }
1828 ++p;
1829 }
1830 }
1831 ++q;
1832 }
1833 }
1834 // Flush the remaining string. This will be the entire
1835 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 Print( "%s", p );
1838 }
Lee Thomason857b8682012-01-25 17:50:25 -08001839}
1840
U-Stream\Leeae25a442012-02-17 17:48:16 -08001841
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001842void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001843{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1845 if ( writeBOM ) {
1846 Print( "%s", bom );
1847 }
1848 if ( writeDec ) {
1849 PushDeclaration( "xml version=\"1.0\"" );
1850 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001851}
1852
1853
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001854void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001855{
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 SealElement();
1858 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001860
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001865
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 _elementJustOpened = true;
1868 _firstElement = false;
1869 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001870}
1871
1872
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001873void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001874{
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 Print( " %s=\"", name );
1877 PrintString( value, false );
1878 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001879}
1880
1881
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001882void XMLPrinter::PushAttribute( const char* name, int v )
1883{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 char buf[BUF_SIZE];
1885 XMLUtil::ToStr( v, buf, BUF_SIZE );
1886 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001887}
1888
1889
1890void XMLPrinter::PushAttribute( const char* name, unsigned v )
1891{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 char buf[BUF_SIZE];
1893 XMLUtil::ToStr( v, buf, BUF_SIZE );
1894 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001895}
1896
1897
1898void XMLPrinter::PushAttribute( const char* name, bool v )
1899{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 char buf[BUF_SIZE];
1901 XMLUtil::ToStr( v, buf, BUF_SIZE );
1902 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001903}
1904
1905
1906void XMLPrinter::PushAttribute( const char* name, double v )
1907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 char buf[BUF_SIZE];
1909 XMLUtil::ToStr( v, buf, BUF_SIZE );
1910 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001911}
1912
1913
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001914void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001915{
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 --_depth;
1917 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001918
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 Print( "/>" );
1921 }
1922 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 }
1927 Print( "</%s>", name );
1928 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001929
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 if ( _textDepth == _depth ) {
1931 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 Print( "\n" );
1935 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001937}
1938
1939
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001940void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001941{
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001944}
1945
1946
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001947void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001948{
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 SealElement();
1953 }
1954 if ( cdata ) {
1955 Print( "<![CDATA[" );
1956 Print( "%s", text );
1957 Print( "]]>" );
1958 }
1959 else {
1960 PrintString( text, true );
1961 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001962}
1963
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001964void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001965{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 char buf[BUF_SIZE];
1967 XMLUtil::ToStr( value, buf, BUF_SIZE );
1968 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001969}
1970
1971
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001972void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 char buf[BUF_SIZE];
1975 XMLUtil::ToStr( value, buf, BUF_SIZE );
1976 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001977}
1978
1979
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001980void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001982 char buf[BUF_SIZE];
1983 XMLUtil::ToStr( value, buf, BUF_SIZE );
1984 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001985}
1986
1987
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001988void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 char buf[BUF_SIZE];
1991 XMLUtil::ToStr( value, buf, BUF_SIZE );
1992 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001993}
1994
1995
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001996void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 char buf[BUF_SIZE];
1999 XMLUtil::ToStr( value, buf, BUF_SIZE );
2000 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002001}
2002
Lee Thomason5cae8972012-01-24 18:03:07 -08002003
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002004void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002005{
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 SealElement();
2008 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002009 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002015}
Lee Thomason751da522012-02-10 08:50:51 -08002016
2017
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002018void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002019{
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 SealElement();
2022 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002029}
2030
2031
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002032void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002033{
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 SealElement();
2036 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002043}
2044
2045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002046bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002047{
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 if ( doc.HasBOM() ) {
2050 PushHeader( true, false );
2051 }
2052 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002053}
2054
2055
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002056bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 OpenElement( element.Name() );
2059 while ( attribute ) {
2060 PushAttribute( attribute->Name(), attribute->Value() );
2061 attribute = attribute->Next();
2062 }
2063 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002064}
2065
2066
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002067bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 CloseElement();
2070 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002071}
2072
2073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 PushText( text.Value(), text.CData() );
2077 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002078}
2079
2080
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002081bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 PushComment( comment.Value() );
2084 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002085}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002087bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 PushDeclaration( declaration.Value() );
2090 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002091}
2092
2093
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002094bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 PushUnknown( unknown.Value() );
2097 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002098}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002099
Lee Thomason685b8952012-11-12 13:00:06 -08002100} // namespace tinyxml2
2101