blob: 61e9b58b2952250a49ce806dc2ff807c8510f691 [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]);
329 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800330}
331
332
333const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 // Presume an entity, and pull it out.
336 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800337
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 if ( *(p+1) == '#' && *(p+2) ) {
339 unsigned long ucs = 0;
340 ptrdiff_t delta = 0;
341 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 if ( *(p+2) == 'x' ) {
344 // Hexadecimal.
345 if ( !*(p+3) ) {
346 return 0;
347 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 const char* q = p+3;
350 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( !q || !*q ) {
353 return 0;
354 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 delta = q-p;
357 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 while ( *q != 'x' ) {
360 if ( *q >= '0' && *q <= '9' ) {
361 ucs += mult * (*q - '0');
362 }
363 else if ( *q >= 'a' && *q <= 'f' ) {
364 ucs += mult * (*q - 'a' + 10);
365 }
366 else if ( *q >= 'A' && *q <= 'F' ) {
367 ucs += mult * (*q - 'A' + 10 );
368 }
369 else {
370 return 0;
371 }
372 mult *= 16;
373 --q;
374 }
375 }
376 else {
377 // Decimal.
378 if ( !*(p+2) ) {
379 return 0;
380 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 const char* q = p+2;
383 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 if ( !q || !*q ) {
386 return 0;
387 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 delta = q-p;
390 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 while ( *q != '#' ) {
393 if ( *q >= '0' && *q <= '9' ) {
394 ucs += mult * (*q - '0');
395 }
396 else {
397 return 0;
398 }
399 mult *= 10;
400 --q;
401 }
402 }
403 // convert the UCS to UTF-8
404 ConvertUTF32ToUTF8( ucs, value, length );
405 return p + delta + 1;
406 }
407 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800409
410
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700411void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700413 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700414}
415
416
417void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700420}
421
422
423void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700426}
427
428
429void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700432}
433
434
435void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441bool XMLUtil::ToInt( const char* str, int* value )
442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
444 return true;
445 }
446 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
449bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
452 return true;
453 }
454 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457bool XMLUtil::ToBool( const char* str, bool* value )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 int ival = 0;
460 if ( ToInt( str, &ival )) {
461 *value = (ival==0) ? false : true;
462 return true;
463 }
464 if ( StringEqual( str, "true" ) ) {
465 *value = true;
466 return true;
467 }
468 else if ( StringEqual( str, "false" ) ) {
469 *value = false;
470 return true;
471 }
472 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700473}
474
475
476bool XMLUtil::ToFloat( const char* str, float* value )
477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
479 return true;
480 }
481 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484bool XMLUtil::ToDouble( const char* str, double* value )
485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700493char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 XMLNode* returnNode = 0;
496 char* start = p;
497 p = XMLUtil::SkipWhiteSpace( p );
498 if( !p || !*p ) {
499 return p;
500 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 // What is this thing?
503 // - Elements start with a letter or underscore, but xml is reserved.
504 // - Comments: <!--
505 // - Decleration: <?
506 // - Everthing else is unknown to tinyxml.
507 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 static const char* xmlHeader = { "<?" };
510 static const char* commentHeader = { "<!--" };
511 static const char* dtdHeader = { "<!" };
512 static const char* cdataHeader = { "<![CDATA[" };
513 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 static const int xmlHeaderLen = 2;
516 static const int commentHeaderLen = 4;
517 static const int dtdHeaderLen = 2;
518 static const int cdataHeaderLen = 9;
519 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800520
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800521#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800522#pragma warning ( push )
523#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
526 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800527#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800528#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
532 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 p += xmlHeaderLen;
534 }
535 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700536 returnNode = new (_commentPool.Alloc()) XMLComment( this );
537 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 p += commentHeaderLen;
539 }
540 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700541 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += cdataHeaderLen;
545 text->SetCData( true );
546 }
547 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
549 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += dtdHeaderLen;
551 }
552 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 returnNode = new (_elementPool.Alloc()) XMLElement( this );
554 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p += elementHeaderLen;
556 }
557 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_textPool.Alloc()) XMLText( this );
559 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p = start; // Back it up, all the text counts.
561 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 *node = returnNode;
564 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800565}
566
567
Lee Thomason751da522012-02-10 08:50:51 -0800568bool XMLDocument::Accept( XMLVisitor* visitor ) const
569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 if ( visitor->VisitEnter( *this ) ) {
571 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
572 if ( !node->Accept( visitor ) ) {
573 break;
574 }
575 }
576 }
577 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800578}
Lee Thomason56bdd022012-02-09 18:16:58 -0800579
580
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800581// --------- XMLNode ----------- //
582
583XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700584 _document( doc ),
585 _parent( 0 ),
586 _firstChild( 0 ), _lastChild( 0 ),
587 _prev( 0 ), _next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800589}
590
591
592XMLNode::~XMLNode()
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 if ( _parent ) {
596 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800598}
599
600
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800601void XMLNode::SetValue( const char* str, bool staticMem )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 }
606 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800609}
610
611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800612void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613{
Lee Thomason624d43f2012-10-12 10:58:48 -0700614 while( _firstChild ) {
615 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700617
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 DELETE_NODE( node );
619 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800621}
622
623
624void XMLNode::Unlink( XMLNode* child )
625{
Lee Thomason624d43f2012-10-12 10:58:48 -0700626 TIXMLASSERT( child->_parent == this );
627 if ( child == _firstChild ) {
628 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 if ( child == _lastChild ) {
631 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 }
Lee Thomasond923c672012-01-23 08:44:25 -0800633
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 if ( child->_prev ) {
635 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child->_next ) {
638 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641}
642
643
U-Stream\Leeae25a442012-02-17 17:48:16 -0800644void XMLNode::DeleteChild( XMLNode* node )
645{
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800648}
649
650
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652{
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 if ( _lastChild ) {
654 TIXMLASSERT( _firstChild );
655 TIXMLASSERT( _lastChild->_next == 0 );
656 _lastChild->_next = addThis;
657 addThis->_prev = _lastChild;
658 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
662 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 TIXMLASSERT( _firstChild == 0 );
664 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 addThis->_prev = 0;
667 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800670 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800672}
673
674
Lee Thomason1ff38e02012-02-14 18:18:16 -0800675XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
676{
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 if ( _firstChild ) {
678 TIXMLASSERT( _lastChild );
679 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800680
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 _firstChild->_prev = addThis;
682 addThis->_next = _firstChild;
683 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800684
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
687 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 TIXMLASSERT( _lastChild == 0 );
689 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800690
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 addThis->_prev = 0;
692 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800695 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 TIXMLASSERT( afterThis->_parent == this );
703 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 return 0;
705 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 // The last node or the only node.
709 return InsertEndChild( addThis );
710 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 addThis->_prev = afterThis;
712 addThis->_next = afterThis->_next;
713 afterThis->_next->_prev = addThis;
714 afterThis->_next = addThis;
715 addThis->_parent = this;
Lee Thomason5b0a6772012-11-19 13:54:42 -0800716 addThis->_memPool->SetTracked();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718}
719
720
721
722
Lee Thomason56bdd022012-02-09 18:16:58 -0800723const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800724{
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 XMLElement* element = node->ToElement();
727 if ( element ) {
728 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
729 return element;
730 }
731 }
732 }
733 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800734}
735
736
Lee Thomason56bdd022012-02-09 18:16:58 -0800737const XMLElement* XMLNode::LastChildElement( const char* value ) const
738{
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 XMLElement* element = node->ToElement();
741 if ( element ) {
742 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
743 return element;
744 }
745 }
746 }
747 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800748}
749
750
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800751const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
752{
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 if ( element->ToElement()
755 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
756 return element->ToElement();
757 }
758 }
759 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800760}
761
762
763const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 if ( element->ToElement()
767 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
768 return element->ToElement();
769 }
770 }
771 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772}
773
774
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800775char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800776{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 // This is a recursive method, but thinking about it "at the current level"
778 // it is a pretty simple flat list:
779 // <foo/>
780 // <!-- comment -->
781 //
782 // With a special case:
783 // <foo>
784 // </foo>
785 // <!-- comment -->
786 //
787 // Where the closing element (/foo) *must* be the next thing after the opening
788 // element, and the names must match. BUT the tricky bit is that the closing
789 // element will be read by the child.
790 //
791 // 'endTag' is the end tag for this node, it is returned by a call to a child.
792 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800793
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 while( p && *p ) {
795 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800796
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 if ( p == 0 || node == 0 ) {
799 break;
800 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800801
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 StrPair endTag;
803 p = node->ParseDeep( p, &endTag );
804 if ( !p ) {
805 DELETE_NODE( node );
806 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 if ( !_document->Error() ) {
808 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
810 break;
811 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800812
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 // We read the end tag. Return it to the parent.
814 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
815 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800818 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 DELETE_NODE( node );
820 return p;
821 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800822
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // Handle an end tag returned to this level.
824 // And handle a bunch of annoying errors.
825 XMLElement* ele = node->ToElement();
826 if ( ele ) {
827 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 p = 0;
830 }
831 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 p = 0;
834 }
835 else if ( !endTag.Empty() ) {
836 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 p = 0;
839 }
840 }
841 }
842 if ( p == 0 ) {
843 DELETE_NODE( node );
844 node = 0;
845 }
846 if ( node ) {
847 this->InsertEndChild( node );
848 }
849 }
850 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800851}
852
Lee Thomason5492a1c2012-01-23 15:32:10 -0800853// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800854char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800855{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 const char* start = p;
857 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 }
862 return p;
863 }
864 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
866 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 flags |= StrPair::COLLAPSE_WHITESPACE;
868 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700869
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
874 if ( p && *p ) {
875 return p-1;
876 }
877 }
878 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800879}
880
881
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800882XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
883{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
888 text->SetCData( this->CData() );
889 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800890}
891
892
893bool XMLText::ShallowEqual( const XMLNode* compare ) const
894{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800896}
897
898
Lee Thomason56bdd022012-02-09 18:16:58 -0800899bool XMLText::Accept( XMLVisitor* visitor ) const
900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800902}
903
904
Lee Thomason3f57d272012-01-11 15:30:03 -0800905// --------- XMLComment ---------- //
906
Lee Thomasone4422302012-01-20 17:59:50 -0800907XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800908{
909}
910
911
Lee Thomasonce0763e2012-01-11 15:43:54 -0800912XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800913{
Lee Thomason3f57d272012-01-11 15:30:03 -0800914}
915
916
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800917char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 // Comment parses as text.
920 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
925 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800926}
927
928
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800929XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
930{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700932 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 }
934 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
935 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800936}
937
938
939bool XMLComment::ShallowEqual( const XMLNode* compare ) const
940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason751da522012-02-10 08:50:51 -0800945bool XMLComment::Accept( XMLVisitor* visitor ) const
946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800948}
Lee Thomason56bdd022012-02-09 18:16:58 -0800949
950
Lee Thomason50f97b22012-02-11 16:33:40 -0800951// --------- XMLDeclaration ---------- //
952
953XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
954{
955}
956
957
958XMLDeclaration::~XMLDeclaration()
959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800961}
962
963
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800964char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800965{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 // Declaration parses as text.
967 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700970 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 }
972 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800973}
974
975
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
977{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
982 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800983}
984
985
986bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989}
990
991
992
Lee Thomason50f97b22012-02-11 16:33:40 -0800993bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800996}
997
998// --------- XMLUnknown ---------- //
999
1000XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1001{
1002}
1003
1004
1005XMLUnknown::~XMLUnknown()
1006{
1007}
1008
1009
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001010char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 // Unknown parses as text.
1013 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001014
Lee Thomason624d43f2012-10-12 10:58:48 -07001015 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
1019 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001020}
1021
1022
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001026 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 }
1028 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1029 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001030}
1031
1032
1033bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001036}
1037
1038
Lee Thomason50f97b22012-02-11 16:33:40 -08001039bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001042}
1043
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001044// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001045char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( !p || !*p ) {
1050 return 0;
1051 }
Lee Thomason22aead12012-01-23 13:29:35 -08001052
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001053 // Skip white space before =
1054 p = XMLUtil::SkipWhiteSpace( p );
1055 if ( !p || *p != '=' ) {
1056 return 0;
1057 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001058
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 ++p; // move up to opening quote
1060 p = XMLUtil::SkipWhiteSpace( p );
1061 if ( *p != '\"' && *p != '\'' ) {
1062 return 0;
1063 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001064
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 char endTag[2] = { *p, 0 };
1066 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001067
Lee Thomason624d43f2012-10-12 10:58:48 -07001068 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001070}
1071
1072
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001073void XMLAttribute::SetName( const char* n )
1074{
Lee Thomason624d43f2012-10-12 10:58:48 -07001075 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001076}
1077
1078
Lee Thomason2fa81722012-11-09 12:37:46 -08001079XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 if ( XMLUtil::ToInt( Value(), value )) {
1082 return XML_NO_ERROR;
1083 }
1084 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001085}
1086
1087
Lee Thomason2fa81722012-11-09 12:37:46 -08001088XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 if ( XMLUtil::ToUnsigned( Value(), value )) {
1091 return XML_NO_ERROR;
1092 }
1093 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001094}
1095
1096
Lee Thomason2fa81722012-11-09 12:37:46 -08001097XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 if ( XMLUtil::ToBool( Value(), value )) {
1100 return XML_NO_ERROR;
1101 }
1102 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001103}
1104
1105
Lee Thomason2fa81722012-11-09 12:37:46 -08001106XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 if ( XMLUtil::ToFloat( Value(), value )) {
1109 return XML_NO_ERROR;
1110 }
1111 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001112}
1113
1114
Lee Thomason2fa81722012-11-09 12:37:46 -08001115XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 if ( XMLUtil::ToDouble( Value(), value )) {
1118 return XML_NO_ERROR;
1119 }
1120 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001121}
1122
1123
1124void XMLAttribute::SetAttribute( const char* v )
1125{
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130void XMLAttribute::SetAttribute( int v )
1131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 char buf[BUF_SIZE];
1133 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001134 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001136
1137
1138void XMLAttribute::SetAttribute( unsigned v )
1139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 char buf[BUF_SIZE];
1141 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001142 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001143}
1144
1145
1146void XMLAttribute::SetAttribute( bool v )
1147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 char buf[BUF_SIZE];
1149 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001150 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001151}
1152
1153void XMLAttribute::SetAttribute( double v )
1154{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 char buf[BUF_SIZE];
1156 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001158}
1159
1160void XMLAttribute::SetAttribute( float v )
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 char buf[BUF_SIZE];
1163 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001165}
1166
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001167
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001168// --------- XMLElement ---------- //
1169XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001170 _closingType( 0 ),
1171 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001172{
1173}
1174
1175
1176XMLElement::~XMLElement()
1177{
Lee Thomason624d43f2012-10-12 10:58:48 -07001178 while( _rootAttribute ) {
1179 XMLAttribute* next = _rootAttribute->_next;
1180 DELETE_ATTRIBUTE( _rootAttribute );
1181 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001183}
1184
1185
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001186XMLAttribute* XMLElement::FindAttribute( const char* name )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1191 return a;
1192 }
1193 }
1194 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001195}
1196
1197
1198const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1203 return a;
1204 }
1205 }
1206 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001207}
1208
1209
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001210const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 const XMLAttribute* a = FindAttribute( name );
1213 if ( !a ) {
1214 return 0;
1215 }
1216 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1217 return a->Value();
1218 }
1219 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001220}
1221
1222
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001223const char* XMLElement::GetText() const
1224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 if ( FirstChild() && FirstChild()->ToText() ) {
1226 return FirstChild()->ToText()->Value();
1227 }
1228 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001229}
1230
1231
Lee Thomason2fa81722012-11-09 12:37:46 -08001232XMLError XMLElement::QueryIntText( int* _value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 if ( FirstChild() && FirstChild()->ToText() ) {
1235 const char* t = FirstChild()->ToText()->Value();
1236 if ( XMLUtil::ToInt( t, _value ) ) {
1237 return XML_SUCCESS;
1238 }
1239 return XML_CAN_NOT_CONVERT_TEXT;
1240 }
1241 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001242}
1243
1244
Lee Thomason2fa81722012-11-09 12:37:46 -08001245XMLError XMLElement::QueryUnsignedText( unsigned* _value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 if ( FirstChild() && FirstChild()->ToText() ) {
1248 const char* t = FirstChild()->ToText()->Value();
1249 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1250 return XML_SUCCESS;
1251 }
1252 return XML_CAN_NOT_CONVERT_TEXT;
1253 }
1254 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001255}
1256
1257
Lee Thomason2fa81722012-11-09 12:37:46 -08001258XMLError XMLElement::QueryBoolText( bool* _value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( FirstChild() && FirstChild()->ToText() ) {
1261 const char* t = FirstChild()->ToText()->Value();
1262 if ( XMLUtil::ToBool( t, _value ) ) {
1263 return XML_SUCCESS;
1264 }
1265 return XML_CAN_NOT_CONVERT_TEXT;
1266 }
1267 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001268}
1269
1270
Lee Thomason2fa81722012-11-09 12:37:46 -08001271XMLError XMLElement::QueryDoubleText( double* _value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( FirstChild() && FirstChild()->ToText() ) {
1274 const char* t = FirstChild()->ToText()->Value();
1275 if ( XMLUtil::ToDouble( t, _value ) ) {
1276 return XML_SUCCESS;
1277 }
1278 return XML_CAN_NOT_CONVERT_TEXT;
1279 }
1280 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001281}
1282
1283
Lee Thomason2fa81722012-11-09 12:37:46 -08001284XMLError XMLElement::QueryFloatText( float* _value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( FirstChild() && FirstChild()->ToText() ) {
1287 const char* t = FirstChild()->ToText()->Value();
1288 if ( XMLUtil::ToFloat( t, _value ) ) {
1289 return XML_SUCCESS;
1290 }
1291 return XML_CAN_NOT_CONVERT_TEXT;
1292 }
1293 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001294}
1295
1296
1297
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001298XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 XMLAttribute* last = 0;
1301 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001302 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001304 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1306 break;
1307 }
1308 }
1309 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001310 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1311 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001316 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 }
1318 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001319 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 }
1321 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001322}
1323
1324
U-Stream\Leeae25a442012-02-17 17:48:16 -08001325void XMLElement::DeleteAttribute( const char* name )
1326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1330 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001331 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 }
1333 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001334 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 }
1336 DELETE_ATTRIBUTE( a );
1337 break;
1338 }
1339 prev = a;
1340 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001341}
1342
1343
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001344char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 const char* start = p;
1347 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001348
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 // Read the attributes.
1350 while( p ) {
1351 p = XMLUtil::SkipWhiteSpace( p );
1352 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001353 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 return 0;
1355 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001356
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 // attribute.
1358 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1360 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001361 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001362
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 if ( !p || Attribute( attrib->Name() ) ) {
1365 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001366 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 return 0;
1368 }
1369 // There is a minor bug here: if the attribute in the source xml
1370 // document is duplicated, it will not be detected and the
1371 // attribute will be doubly added. However, tracking the 'prevAttribute'
1372 // avoids re-scanning the attribute list. Preferring performance for
1373 // now, may reconsider in the future.
1374 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 }
1377 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001378 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 }
1380 prevAttribute = attrib;
1381 }
1382 // end of the tag
1383 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001384 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 return p+2; // done; sealed element.
1386 }
1387 // end of the tag
1388 else if ( *p == '>' ) {
1389 ++p;
1390 break;
1391 }
1392 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001393 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return 0;
1395 }
1396 }
1397 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001398}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001399
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001400
Lee Thomason67d61312012-01-24 16:01:51 -08001401//
1402// <ele></ele>
1403// <ele>foo<b>bar</b></ele>
1404//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001405char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 // Read the element name.
1408 p = XMLUtil::SkipWhiteSpace( p );
1409 if ( !p ) {
1410 return 0;
1411 }
Lee Thomason67d61312012-01-24 16:01:51 -08001412
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 // The closing element is the </element> form. It is
1414 // parsed just like a regular element then deleted from
1415 // the DOM.
1416 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 ++p;
1419 }
Lee Thomason67d61312012-01-24 16:01:51 -08001420
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 p = _value.ParseName( p );
1422 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 return 0;
1424 }
Lee Thomason67d61312012-01-24 16:01:51 -08001425
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 return p;
1429 }
Lee Thomason67d61312012-01-24 16:01:51 -08001430
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 p = XMLNode::ParseDeep( p, strPair );
1432 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001433}
1434
1435
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001436
1437XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 }
1442 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1443 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1444 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1445 }
1446 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001447}
1448
1449
1450bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 const XMLElement* other = compare->ToElement();
1453 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001454
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 const XMLAttribute* a=FirstAttribute();
1456 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001457
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 while ( a && b ) {
1459 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1460 return false;
1461 }
1462 a = a->Next();
1463 b = b->Next();
1464 }
1465 if ( a || b ) {
1466 // different count
1467 return false;
1468 }
1469 return true;
1470 }
1471 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001472}
1473
1474
Lee Thomason751da522012-02-10 08:50:51 -08001475bool XMLElement::Accept( XMLVisitor* visitor ) const
1476{
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1479 if ( !node->Accept( visitor ) ) {
1480 break;
1481 }
1482 }
1483 }
1484 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001485}
Lee Thomason56bdd022012-02-09 18:16:58 -08001486
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001487
Lee Thomason3f57d272012-01-11 15:30:03 -08001488// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001489XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 _writeBOM( false ),
1492 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001493 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001494 _whitespace( whitespace ),
1495 _errorStr1( 0 ),
1496 _errorStr2( 0 ),
1497 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001498{
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001500}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001501
1502
Lee Thomason3f57d272012-01-11 15:30:03 -08001503XMLDocument::~XMLDocument()
1504{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001507
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001508#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 textPool.Trace( "text" );
1510 elementPool.Trace( "element" );
1511 commentPool.Trace( "comment" );
1512 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001513#endif
1514
Lee Thomason5b0a6772012-11-19 13:54:42 -08001515#ifdef DEBUG
1516 if ( Error() == false ) {
1517 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1518 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1519 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1520 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1521 }
1522#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001523}
1524
1525
Lee Thomason18d68bd2012-01-26 18:17:26 -08001526void XMLDocument::InitDocument()
1527{
Lee Thomason624d43f2012-10-12 10:58:48 -07001528 _errorID = XML_NO_ERROR;
1529 _errorStr1 = 0;
1530 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001531
Lee Thomason624d43f2012-10-12 10:58:48 -07001532 delete [] _charBuffer;
1533 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001534}
1535
Lee Thomason3f57d272012-01-11 15:30:03 -08001536
Lee Thomason2c85a712012-01-31 08:24:24 -08001537XMLElement* XMLDocument::NewElement( const char* name )
1538{
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1540 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 ele->SetName( name );
1542 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001543}
1544
1545
Lee Thomason1ff38e02012-02-14 18:18:16 -08001546XMLComment* XMLDocument::NewComment( const char* str )
1547{
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1549 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 comment->SetValue( str );
1551 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001552}
1553
1554
1555XMLText* XMLDocument::NewText( const char* str )
1556{
Lee Thomason624d43f2012-10-12 10:58:48 -07001557 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1558 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 text->SetValue( str );
1560 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001561}
1562
1563
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001564XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1565{
Lee Thomason624d43f2012-10-12 10:58:48 -07001566 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1567 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1569 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001570}
1571
1572
1573XMLUnknown* XMLDocument::NewUnknown( const char* str )
1574{
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1576 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 unk->SetValue( str );
1578 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579}
1580
1581
Lee Thomason2fa81722012-11-09 12:37:46 -08001582XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 DeleteChildren();
1585 InitDocument();
1586 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1589 errno_t err = fopen_s(&fp, filename, "rb" );
1590 if ( !fp || err) {
1591#else
1592 fp = fopen( filename, "rb" );
1593 if ( !fp) {
1594#endif
1595 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001596 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 }
1598 LoadFile( fp );
1599 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001600 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001601}
1602
1603
Lee Thomason2fa81722012-11-09 12:37:46 -08001604XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 DeleteChildren();
1607 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001608
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 fseek( fp, 0, SEEK_END );
1610 size_t size = ftell( fp );
1611 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001612
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 if ( size == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001616
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 _charBuffer = new char[size+1];
1618 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 if ( read != size ) {
1620 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001623
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001625
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 if ( !p || !*p ) {
1630 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001631 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001633
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1635 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001636}
1637
1638
Lee Thomason2fa81722012-11-09 12:37:46 -08001639XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 FILE* fp = 0;
1642#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1643 errno_t err = fopen_s(&fp, filename, "w" );
1644 if ( !fp || err) {
1645#else
1646 fp = fopen( filename, "w" );
1647 if ( !fp) {
1648#endif
1649 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 }
1652 SaveFile(fp, compact);
1653 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001655}
1656
1657
Lee Thomason2fa81722012-11-09 12:37:46 -08001658XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001659{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 XMLPrinter stream( fp, compact );
1661 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001663}
1664
Lee Thomason1ff38e02012-02-14 18:18:16 -08001665
Lee Thomason2fa81722012-11-09 12:37:46 -08001666XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001667{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 DeleteChildren();
1669 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001670
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 if ( !p || !*p ) {
1672 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 }
1675 if ( len == (size_t)(-1) ) {
1676 len = strlen( p );
1677 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 _charBuffer = new char[ len+1 ];
1679 memcpy( _charBuffer, p, len );
1680 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001681
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 if ( !p || !*p ) {
1685 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001686 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001688
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 ParseDeep( _charBuffer, 0 );
1690 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001691}
1692
1693
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001694void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001695{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 XMLPrinter stdStreamer( stdout );
1697 if ( !streamer ) {
1698 streamer = &stdStreamer;
1699 }
1700 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001701}
1702
1703
Lee Thomason2fa81722012-11-09 12:37:46 -08001704void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001705{
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 _errorID = error;
1707 _errorStr1 = str1;
1708 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001709}
1710
Lee Thomason5cae8972012-01-24 18:03:07 -08001711
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001712void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001713{
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001715 static const int LEN = 20;
1716 char buf1[LEN] = { 0 };
1717 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001718
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 if ( _errorStr1 ) {
1720 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 if ( _errorStr2 ) {
1723 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001725
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001729}
1730
1731
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001732XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 _elementJustOpened( false ),
1734 _firstElement( true ),
1735 _fp( file ),
1736 _depth( 0 ),
1737 _textDepth( -1 ),
1738 _processEntities( true ),
1739 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001740{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 _entityFlag[i] = false;
1743 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 }
1745 for( int i=0; i<NUM_ENTITIES; ++i ) {
1746 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1747 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 }
1750 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 _restrictedEntityFlag[(int)'&'] = true;
1752 _restrictedEntityFlag[(int)'<'] = true;
1753 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1754 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001755}
1756
1757
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001758void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001759{
1760 va_list va;
1761 va_start( va, format );
1762
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 if ( _fp ) {
1764 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 }
1766 else {
1767 // This seems brutally complex. Haven't figured out a better
1768 // way on windows.
1769#ifdef _MSC_VER
1770 int len = -1;
1771 int expand = 1000;
1772 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 if ( len < 0 ) {
1775 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001776 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 }
1778 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 char* p = _buffer.PushArr( len ) - 1;
1780 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781#else
1782 int len = vsnprintf( 0, 0, format, va );
1783 // Close out and re-start the va-args
1784 va_end( va );
1785 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 vsnprintf( p, len+1, format, va );
1788#endif
1789 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001790 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001791}
1792
1793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001794void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001795{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 for( int i=0; i<depth; ++i ) {
1797 Print( " " );
1798 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001799}
1800
1801
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001802void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001803{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 // Look for runs of bytes between entities to print.
1805 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001807
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 while ( *q ) {
1810 // Remember, char is sometimes signed. (How many times has that bitten me?)
1811 if ( *q > 0 && *q < ENTITY_RANGE ) {
1812 // Check for entities. If one is found, flush
1813 // the stream up until the entity, write the
1814 // entity, and keep looking.
1815 if ( flag[(unsigned)(*q)] ) {
1816 while ( p < q ) {
1817 Print( "%c", *p );
1818 ++p;
1819 }
1820 for( int i=0; i<NUM_ENTITIES; ++i ) {
1821 if ( entities[i].value == *q ) {
1822 Print( "&%s;", entities[i].pattern );
1823 break;
1824 }
1825 }
1826 ++p;
1827 }
1828 }
1829 ++q;
1830 }
1831 }
1832 // Flush the remaining string. This will be the entire
1833 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 Print( "%s", p );
1836 }
Lee Thomason857b8682012-01-25 17:50:25 -08001837}
1838
U-Stream\Leeae25a442012-02-17 17:48:16 -08001839
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001840void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001841{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1843 if ( writeBOM ) {
1844 Print( "%s", bom );
1845 }
1846 if ( writeDec ) {
1847 PushDeclaration( "xml version=\"1.0\"" );
1848 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001849}
1850
1851
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001852void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001853{
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 SealElement();
1856 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001858
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001863
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 _elementJustOpened = true;
1866 _firstElement = false;
1867 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001868}
1869
1870
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001871void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001872{
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 Print( " %s=\"", name );
1875 PrintString( value, false );
1876 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001877}
1878
1879
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001880void XMLPrinter::PushAttribute( const char* name, int v )
1881{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 char buf[BUF_SIZE];
1883 XMLUtil::ToStr( v, buf, BUF_SIZE );
1884 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001885}
1886
1887
1888void XMLPrinter::PushAttribute( const char* name, unsigned v )
1889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 char buf[BUF_SIZE];
1891 XMLUtil::ToStr( v, buf, BUF_SIZE );
1892 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001893}
1894
1895
1896void XMLPrinter::PushAttribute( const char* name, bool v )
1897{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 char buf[BUF_SIZE];
1899 XMLUtil::ToStr( v, buf, BUF_SIZE );
1900 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001901}
1902
1903
1904void XMLPrinter::PushAttribute( const char* name, double v )
1905{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 char buf[BUF_SIZE];
1907 XMLUtil::ToStr( v, buf, BUF_SIZE );
1908 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001909}
1910
1911
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001912void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001913{
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 --_depth;
1915 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001916
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 Print( "/>" );
1919 }
1920 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 }
1925 Print( "</%s>", name );
1926 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001927
Lee Thomason624d43f2012-10-12 10:58:48 -07001928 if ( _textDepth == _depth ) {
1929 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001931 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 Print( "\n" );
1933 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001935}
1936
1937
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001938void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001939{
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001942}
1943
1944
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001945void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001946{
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001948
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 SealElement();
1951 }
1952 if ( cdata ) {
1953 Print( "<![CDATA[" );
1954 Print( "%s", text );
1955 Print( "]]>" );
1956 }
1957 else {
1958 PrintString( text, true );
1959 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001960}
1961
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001962void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 char buf[BUF_SIZE];
1965 XMLUtil::ToStr( value, buf, BUF_SIZE );
1966 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001967}
1968
1969
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001970void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001971{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 char buf[BUF_SIZE];
1973 XMLUtil::ToStr( value, buf, BUF_SIZE );
1974 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001975}
1976
1977
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001978void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 char buf[BUF_SIZE];
1981 XMLUtil::ToStr( value, buf, BUF_SIZE );
1982 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001983}
1984
1985
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001986void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 char buf[BUF_SIZE];
1989 XMLUtil::ToStr( value, buf, BUF_SIZE );
1990 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001991}
1992
1993
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001994void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 char buf[BUF_SIZE];
1997 XMLUtil::ToStr( value, buf, BUF_SIZE );
1998 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001999}
2000
Lee Thomason5cae8972012-01-24 18:03:07 -08002001
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002002void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002003{
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 SealElement();
2006 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002009 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
Lee Thomason751da522012-02-10 08:50:51 -08002014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002017{
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 SealElement();
2020 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002027}
2028
2029
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002030void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002031{
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 SealElement();
2034 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002041}
2042
2043
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002044bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002045{
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 if ( doc.HasBOM() ) {
2048 PushHeader( true, false );
2049 }
2050 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002051}
2052
2053
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002054bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 OpenElement( element.Name() );
2057 while ( attribute ) {
2058 PushAttribute( attribute->Name(), attribute->Value() );
2059 attribute = attribute->Next();
2060 }
2061 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002062}
2063
2064
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002065bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002066{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 CloseElement();
2068 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002069}
2070
2071
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002072bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002073{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 PushText( text.Value(), text.CData() );
2075 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002076}
2077
2078
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002079bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 PushComment( comment.Value() );
2082 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002083}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002084
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002085bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 PushDeclaration( declaration.Value() );
2088 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002089}
2090
2091
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002092bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 PushUnknown( unknown.Value() );
2095 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002096}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002097
Lee Thomason685b8952012-11-12 13:00:06 -08002098} // namespace tinyxml2
2099