blob: 7ecbf867b5bcece4a7e21a326437bfede85663e6 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
414void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700417}
418
419
420void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
425
426void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
427{
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700428 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700429}
430
431
432void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
433{
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700434 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700435}
436
437
438bool XMLUtil::ToInt( const char* str, int* value )
439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
441 return true;
442 }
443 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700444}
445
446bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700448 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
449 return true;
450 }
451 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454bool XMLUtil::ToBool( const char* str, bool* value )
455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 int ival = 0;
457 if ( ToInt( str, &ival )) {
458 *value = (ival==0) ? false : true;
459 return true;
460 }
461 if ( StringEqual( str, "true" ) ) {
462 *value = true;
463 return true;
464 }
465 else if ( StringEqual( str, "false" ) ) {
466 *value = false;
467 return true;
468 }
469 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700470}
471
472
473bool XMLUtil::ToFloat( const char* str, float* value )
474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
476 return true;
477 }
478 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700479}
480
481bool XMLUtil::ToDouble( const char* str, double* value )
482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700490char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 XMLNode* returnNode = 0;
493 char* start = p;
494 p = XMLUtil::SkipWhiteSpace( p );
495 if( !p || !*p ) {
496 return p;
497 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 // What is this thing?
500 // - Elements start with a letter or underscore, but xml is reserved.
501 // - Comments: <!--
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700502 // - Declaration: <?
503 // - Everything else is unknown to tinyxml.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 static const char* xmlHeader = { "<?" };
507 static const char* commentHeader = { "<!--" };
508 static const char* dtdHeader = { "<!" };
509 static const char* cdataHeader = { "<![CDATA[" };
510 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 static const int xmlHeaderLen = 2;
513 static const int commentHeaderLen = 4;
514 static const int dtdHeaderLen = 2;
515 static const int cdataHeaderLen = 9;
516 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800518#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800519#pragma warning ( push )
520#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800521#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
523 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800525#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700528 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
529 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 p += xmlHeaderLen;
531 }
532 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode = new (_commentPool.Alloc()) XMLComment( this );
534 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 p += commentHeaderLen;
536 }
537 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 p += cdataHeaderLen;
542 text->SetCData( true );
543 }
544 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += dtdHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 returnNode = new (_elementPool.Alloc()) XMLElement( this );
551 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += elementHeaderLen;
553 }
554 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_textPool.Alloc()) XMLText( this );
556 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p = start; // Back it up, all the text counts.
558 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800559
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 *node = returnNode;
561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562}
563
564
Lee Thomason751da522012-02-10 08:50:51 -0800565bool XMLDocument::Accept( XMLVisitor* visitor ) const
566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( visitor->VisitEnter( *this ) ) {
568 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
569 if ( !node->Accept( visitor ) ) {
570 break;
571 }
572 }
573 }
574 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800575}
Lee Thomason56bdd022012-02-09 18:16:58 -0800576
577
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800578// --------- XMLNode ----------- //
579
580XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 _document( doc ),
582 _parent( 0 ),
583 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200584 _prev( 0 ), _next( 0 ),
585 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587}
588
589
590XMLNode::~XMLNode()
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 if ( _parent ) {
594 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800596}
597
Michael Daumling21626882013-10-22 17:03:37 +0200598const char* XMLNode::Value() const
599{
600 return _value.GetStr();
601}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800602
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603void XMLNode::SetValue( const char* str, bool staticMem )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
608 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800611}
612
613
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800614void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800615{
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 while( _firstChild ) {
617 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700619
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 DELETE_NODE( node );
621 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700622 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800623}
624
625
626void XMLNode::Unlink( XMLNode* child )
627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 if ( child == _firstChild ) {
629 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( child == _lastChild ) {
632 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomasond923c672012-01-23 08:44:25 -0800634
Lee Thomason624d43f2012-10-12 10:58:48 -0700635 if ( child->_prev ) {
636 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 if ( child->_next ) {
639 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641}
642
643
U-Stream\Leeae25a442012-02-17 17:48:16 -0800644void XMLNode::DeleteChild( XMLNode* node )
645{
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800648}
649
650
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652{
Michael Daumlinged523282013-10-23 07:47:29 +0200653 if (addThis->_document != _document)
654 return 0;
655 if (addThis->_parent)
656 addThis->_parent->Unlink( addThis );
657 else
658 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( _lastChild ) {
660 TIXMLASSERT( _firstChild );
661 TIXMLASSERT( _lastChild->_next == 0 );
662 _lastChild->_next = addThis;
663 addThis->_prev = _lastChild;
664 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 }
668 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 TIXMLASSERT( _firstChild == 0 );
670 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 addThis->_prev = 0;
673 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677}
678
679
Lee Thomason1ff38e02012-02-14 18:18:16 -0800680XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
681{
Michael Daumlinged523282013-10-23 07:47:29 +0200682 if (addThis->_document != _document)
683 return 0;
684 if (addThis->_parent)
685 addThis->_parent->Unlink( addThis );
686 else
687 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( _firstChild ) {
689 TIXMLASSERT( _lastChild );
690 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 _firstChild->_prev = addThis;
693 addThis->_next = _firstChild;
694 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 }
698 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 TIXMLASSERT( _lastChild == 0 );
700 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 addThis->_prev = 0;
703 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200706 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800707}
708
709
710XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
711{
Michael Daumlinged523282013-10-23 07:47:29 +0200712 if (addThis->_document != _document)
713 return 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700714 TIXMLASSERT( afterThis->_parent == this );
715 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 return 0;
717 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 // The last node or the only node.
721 return InsertEndChild( addThis );
722 }
Michael Daumlinged523282013-10-23 07:47:29 +0200723 if (addThis->_parent)
724 addThis->_parent->Unlink( addThis );
725 else
726 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_prev = afterThis;
728 addThis->_next = afterThis->_next;
729 afterThis->_next->_prev = addThis;
730 afterThis->_next = addThis;
731 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800733}
734
735
736
737
Lee Thomason56bdd022012-02-09 18:16:58 -0800738const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800739{
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 XMLElement* element = node->ToElement();
742 if ( element ) {
743 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
744 return element;
745 }
746 }
747 }
748 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800749}
750
751
Lee Thomason56bdd022012-02-09 18:16:58 -0800752const XMLElement* XMLNode::LastChildElement( const char* value ) const
753{
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 XMLElement* element = node->ToElement();
756 if ( element ) {
757 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
758 return element;
759 }
760 }
761 }
762 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800763}
764
765
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800766const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
767{
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 if ( element->ToElement()
770 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
771 return element->ToElement();
772 }
773 }
774 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800775}
776
777
778const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
779{
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 if ( element->ToElement()
782 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
783 return element->ToElement();
784 }
785 }
786 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800787}
788
789
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800790char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800791{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700792 // This is a recursive method, but thinking about it "at the current level"
793 // it is a pretty simple flat list:
794 // <foo/>
795 // <!-- comment -->
796 //
797 // With a special case:
798 // <foo>
799 // </foo>
800 // <!-- comment -->
801 //
802 // Where the closing element (/foo) *must* be the next thing after the opening
803 // element, and the names must match. BUT the tricky bit is that the closing
804 // element will be read by the child.
805 //
806 // 'endTag' is the end tag for this node, it is returned by a call to a child.
807 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800808
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 while( p && *p ) {
810 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800811
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 if ( p == 0 || node == 0 ) {
814 break;
815 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800816
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 StrPair endTag;
818 p = node->ParseDeep( p, &endTag );
819 if ( !p ) {
820 DELETE_NODE( node );
821 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 if ( !_document->Error() ) {
823 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 }
825 break;
826 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800827
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 // We read the end tag. Return it to the parent.
829 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
830 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800833 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 DELETE_NODE( node );
835 return p;
836 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 // Handle an end tag returned to this level.
839 // And handle a bunch of annoying errors.
840 XMLElement* ele = node->ToElement();
841 if ( ele ) {
842 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 p = 0;
845 }
846 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 p = 0;
849 }
850 else if ( !endTag.Empty() ) {
851 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 p = 0;
854 }
855 }
856 }
857 if ( p == 0 ) {
858 DELETE_NODE( node );
859 node = 0;
860 }
861 if ( node ) {
862 this->InsertEndChild( node );
863 }
864 }
865 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800866}
867
Lee Thomason5492a1c2012-01-23 15:32:10 -0800868// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800869char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800870{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 const char* start = p;
872 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700875 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 }
877 return p;
878 }
879 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
881 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 flags |= StrPair::COLLAPSE_WHITESPACE;
883 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700884
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 if ( p && *p ) {
890 return p-1;
891 }
892 }
893 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800894}
895
896
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800897XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700900 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 }
902 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
903 text->SetCData( this->CData() );
904 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905}
906
907
908bool XMLText::ShallowEqual( const XMLNode* compare ) const
909{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700910 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
Lee Thomason56bdd022012-02-09 18:16:58 -0800914bool XMLText::Accept( XMLVisitor* visitor ) const
915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800917}
918
919
Lee Thomason3f57d272012-01-11 15:30:03 -0800920// --------- XMLComment ---------- //
921
Lee Thomasone4422302012-01-20 17:59:50 -0800922XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800923{
924}
925
926
Lee Thomasonce0763e2012-01-11 15:43:54 -0800927XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800928{
Lee Thomason3f57d272012-01-11 15:30:03 -0800929}
930
931
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800932char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800933{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 // Comment parses as text.
935 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700936 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700938 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800941}
942
943
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800944XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
945{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700947 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 }
949 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
950 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951}
952
953
954bool XMLComment::ShallowEqual( const XMLNode* compare ) const
955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957}
958
959
Lee Thomason751da522012-02-10 08:50:51 -0800960bool XMLComment::Accept( XMLVisitor* visitor ) const
961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800963}
Lee Thomason56bdd022012-02-09 18:16:58 -0800964
965
Lee Thomason50f97b22012-02-11 16:33:40 -0800966// --------- XMLDeclaration ---------- //
967
968XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
969{
970}
971
972
973XMLDeclaration::~XMLDeclaration()
974{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800976}
977
978
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800979char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 // Declaration parses as text.
982 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700985 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 }
987 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800988}
989
990
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800991XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 }
996 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
997 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998}
999
1000
1001bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1002{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
1007
Lee Thomason50f97b22012-02-11 16:33:40 -08001008bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001011}
1012
1013// --------- XMLUnknown ---------- //
1014
1015XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1016{
1017}
1018
1019
1020XMLUnknown::~XMLUnknown()
1021{
1022}
1023
1024
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001025char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 // Unknown parses as text.
1028 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001029
Lee Thomason624d43f2012-10-12 10:58:48 -07001030 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001032 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 }
1034 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001035}
1036
1037
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001038XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001041 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 }
1043 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1044 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045}
1046
1047
1048bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
Lee Thomason50f97b22012-02-11 16:33:40 -08001054bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001057}
1058
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001059// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001060
1061const char* XMLAttribute::Name() const
1062{
1063 return _name.GetStr();
1064}
1065
1066const char* XMLAttribute::Value() const
1067{
1068 return _value.GetStr();
1069}
1070
Lee Thomason6f381b72012-03-02 12:59:39 -08001071char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 if ( !p || !*p ) {
1076 return 0;
1077 }
Lee Thomason22aead12012-01-23 13:29:35 -08001078
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Skip white space before =
1080 p = XMLUtil::SkipWhiteSpace( p );
1081 if ( !p || *p != '=' ) {
1082 return 0;
1083 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001084
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 ++p; // move up to opening quote
1086 p = XMLUtil::SkipWhiteSpace( p );
1087 if ( *p != '\"' && *p != '\'' ) {
1088 return 0;
1089 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001090
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 char endTag[2] = { *p, 0 };
1092 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001093
Lee Thomason624d43f2012-10-12 10:58:48 -07001094 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001096}
1097
1098
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001099void XMLAttribute::SetName( const char* n )
1100{
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001102}
1103
1104
Lee Thomason2fa81722012-11-09 12:37:46 -08001105XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 if ( XMLUtil::ToInt( Value(), value )) {
1108 return XML_NO_ERROR;
1109 }
1110 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001111}
1112
1113
Lee Thomason2fa81722012-11-09 12:37:46 -08001114XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 if ( XMLUtil::ToUnsigned( Value(), value )) {
1117 return XML_NO_ERROR;
1118 }
1119 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001120}
1121
1122
Lee Thomason2fa81722012-11-09 12:37:46 -08001123XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( XMLUtil::ToBool( Value(), value )) {
1126 return XML_NO_ERROR;
1127 }
1128 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001129}
1130
1131
Lee Thomason2fa81722012-11-09 12:37:46 -08001132XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 if ( XMLUtil::ToFloat( Value(), value )) {
1135 return XML_NO_ERROR;
1136 }
1137 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001138}
1139
1140
Lee Thomason2fa81722012-11-09 12:37:46 -08001141XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 if ( XMLUtil::ToDouble( Value(), value )) {
1144 return XML_NO_ERROR;
1145 }
1146 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001147}
1148
1149
1150void XMLAttribute::SetAttribute( const char* v )
1151{
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001153}
1154
1155
Lee Thomason1ff38e02012-02-14 18:18:16 -08001156void XMLAttribute::SetAttribute( int v )
1157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 char buf[BUF_SIZE];
1159 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001161}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001162
1163
1164void XMLAttribute::SetAttribute( unsigned v )
1165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 char buf[BUF_SIZE];
1167 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001168 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169}
1170
1171
1172void XMLAttribute::SetAttribute( bool v )
1173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 char buf[BUF_SIZE];
1175 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001176 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001177}
1178
1179void XMLAttribute::SetAttribute( double v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186void XMLAttribute::SetAttribute( float v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001193
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001194// --------- XMLElement ---------- //
1195XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 _closingType( 0 ),
1197 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001198{
1199}
1200
1201
1202XMLElement::~XMLElement()
1203{
Lee Thomason624d43f2012-10-12 10:58:48 -07001204 while( _rootAttribute ) {
1205 XMLAttribute* next = _rootAttribute->_next;
1206 DELETE_ATTRIBUTE( _rootAttribute );
1207 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001209}
1210
1211
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001212XMLAttribute* XMLElement::FindAttribute( const char* name )
1213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001215 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1217 return a;
1218 }
1219 }
1220 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001221}
1222
1223
1224const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1229 return a;
1230 }
1231 }
1232 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001233}
1234
1235
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001236const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 const XMLAttribute* a = FindAttribute( name );
1239 if ( !a ) {
1240 return 0;
1241 }
1242 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1243 return a->Value();
1244 }
1245 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001246}
1247
1248
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001249const char* XMLElement::GetText() const
1250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 if ( FirstChild() && FirstChild()->ToText() ) {
1252 return FirstChild()->ToText()->Value();
1253 }
1254 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001255}
1256
1257
MortenMacFly4ee49f12013-01-14 20:03:14 +01001258XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( FirstChild() && FirstChild()->ToText() ) {
1261 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001262 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 return XML_SUCCESS;
1264 }
1265 return XML_CAN_NOT_CONVERT_TEXT;
1266 }
1267 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001268}
1269
1270
MortenMacFly4ee49f12013-01-14 20:03:14 +01001271XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( FirstChild() && FirstChild()->ToText() ) {
1274 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001275 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 return XML_SUCCESS;
1277 }
1278 return XML_CAN_NOT_CONVERT_TEXT;
1279 }
1280 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001281}
1282
1283
MortenMacFly4ee49f12013-01-14 20:03:14 +01001284XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( FirstChild() && FirstChild()->ToText() ) {
1287 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001288 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 return XML_SUCCESS;
1290 }
1291 return XML_CAN_NOT_CONVERT_TEXT;
1292 }
1293 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001294}
1295
1296
MortenMacFly4ee49f12013-01-14 20:03:14 +01001297XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 if ( FirstChild() && FirstChild()->ToText() ) {
1300 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001301 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 return XML_SUCCESS;
1303 }
1304 return XML_CAN_NOT_CONVERT_TEXT;
1305 }
1306 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001307}
1308
1309
MortenMacFly4ee49f12013-01-14 20:03:14 +01001310XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( FirstChild() && FirstChild()->ToText() ) {
1313 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001314 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 return XML_SUCCESS;
1316 }
1317 return XML_CAN_NOT_CONVERT_TEXT;
1318 }
1319 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001320}
1321
1322
1323
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001324XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1325{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 XMLAttribute* last = 0;
1327 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001330 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1332 break;
1333 }
1334 }
1335 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001336 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1337 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001339 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 }
1341 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001342 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 }
1344 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001345 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001348}
1349
1350
U-Stream\Leeae25a442012-02-17 17:48:16 -08001351void XMLElement::DeleteAttribute( const char* name )
1352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001354 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1356 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001357 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 }
1359 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001360 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 }
1362 DELETE_ATTRIBUTE( a );
1363 break;
1364 }
1365 prev = a;
1366 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001367}
1368
1369
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001370char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 const char* start = p;
1373 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001374
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 // Read the attributes.
1376 while( p ) {
1377 p = XMLUtil::SkipWhiteSpace( p );
1378 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001379 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 return 0;
1381 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001382
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001384 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1386 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001387 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001388
Lee Thomason624d43f2012-10-12 10:58:48 -07001389 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( !p || Attribute( attrib->Name() ) ) {
1391 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 return 0;
1394 }
1395 // There is a minor bug here: if the attribute in the source xml
1396 // document is duplicated, it will not be detected and the
1397 // attribute will be doubly added. However, tracking the 'prevAttribute'
1398 // avoids re-scanning the attribute list. Preferring performance for
1399 // now, may reconsider in the future.
1400 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001404 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 }
1406 prevAttribute = attrib;
1407 }
1408 // end of the tag
1409 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 return p+2; // done; sealed element.
1412 }
1413 // end of the tag
1414 else if ( *p == '>' ) {
1415 ++p;
1416 break;
1417 }
1418 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 return 0;
1421 }
1422 }
1423 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001424}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001425
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001426
Lee Thomason67d61312012-01-24 16:01:51 -08001427//
1428// <ele></ele>
1429// <ele>foo<b>bar</b></ele>
1430//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001431char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 // Read the element name.
1434 p = XMLUtil::SkipWhiteSpace( p );
1435 if ( !p ) {
1436 return 0;
1437 }
Lee Thomason67d61312012-01-24 16:01:51 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 // The closing element is the </element> form. It is
1440 // parsed just like a regular element then deleted from
1441 // the DOM.
1442 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 ++p;
1445 }
Lee Thomason67d61312012-01-24 16:01:51 -08001446
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 p = _value.ParseName( p );
1448 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 return 0;
1450 }
Lee Thomason67d61312012-01-24 16:01:51 -08001451
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 return p;
1455 }
Lee Thomason67d61312012-01-24 16:01:51 -08001456
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 p = XMLNode::ParseDeep( p, strPair );
1458 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001459}
1460
1461
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001462
1463XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001466 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 }
1468 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1469 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1470 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1471 }
1472 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001473}
1474
1475
1476bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 const XMLElement* other = compare->ToElement();
1479 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001480
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 const XMLAttribute* a=FirstAttribute();
1482 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001483
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 while ( a && b ) {
1485 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1486 return false;
1487 }
1488 a = a->Next();
1489 b = b->Next();
1490 }
1491 if ( a || b ) {
1492 // different count
1493 return false;
1494 }
1495 return true;
1496 }
1497 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001498}
1499
1500
Lee Thomason751da522012-02-10 08:50:51 -08001501bool XMLElement::Accept( XMLVisitor* visitor ) const
1502{
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1505 if ( !node->Accept( visitor ) ) {
1506 break;
1507 }
1508 }
1509 }
1510 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001511}
Lee Thomason56bdd022012-02-09 18:16:58 -08001512
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001513
Lee Thomason3f57d272012-01-11 15:30:03 -08001514// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001515XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001517 _writeBOM( false ),
1518 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001519 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 _whitespace( whitespace ),
1521 _errorStr1( 0 ),
1522 _errorStr2( 0 ),
1523 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001524{
Lee Thomason624d43f2012-10-12 10:58:48 -07001525 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001526}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001527
1528
Lee Thomason3f57d272012-01-11 15:30:03 -08001529XMLDocument::~XMLDocument()
1530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001532 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001533
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001534#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001535 _textPool.Trace( "text" );
1536 _elementPool.Trace( "element" );
1537 _commentPool.Trace( "comment" );
1538 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001539#endif
1540
Lee Thomason5b0a6772012-11-19 13:54:42 -08001541#ifdef DEBUG
1542 if ( Error() == false ) {
1543 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1544 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1545 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1546 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1547 }
1548#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001549}
1550
1551
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001552void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001553{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001554 DeleteChildren();
1555
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 _errorID = XML_NO_ERROR;
1557 _errorStr1 = 0;
1558 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001559
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 delete [] _charBuffer;
1561 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001562}
1563
Lee Thomason3f57d272012-01-11 15:30:03 -08001564
Lee Thomason2c85a712012-01-31 08:24:24 -08001565XMLElement* XMLDocument::NewElement( const char* name )
1566{
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1568 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 ele->SetName( name );
1570 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001571}
1572
1573
Lee Thomason1ff38e02012-02-14 18:18:16 -08001574XMLComment* XMLDocument::NewComment( const char* str )
1575{
Lee Thomason624d43f2012-10-12 10:58:48 -07001576 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1577 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 comment->SetValue( str );
1579 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001580}
1581
1582
1583XMLText* XMLDocument::NewText( const char* str )
1584{
Lee Thomason624d43f2012-10-12 10:58:48 -07001585 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1586 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 text->SetValue( str );
1588 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001589}
1590
1591
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001592XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1593{
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1595 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1597 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001598}
1599
1600
1601XMLUnknown* XMLDocument::NewUnknown( const char* str )
1602{
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1604 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 unk->SetValue( str );
1606 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001607}
1608
1609
Lee Thomason2fa81722012-11-09 12:37:46 -08001610XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001611{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001612 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001614
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1616 errno_t err = fopen_s(&fp, filename, "rb" );
1617 if ( !fp || err) {
1618#else
1619 fp = fopen( filename, "rb" );
1620 if ( !fp) {
1621#endif
1622 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
1625 LoadFile( fp );
1626 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001627 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001628}
1629
1630
Lee Thomason2fa81722012-11-09 12:37:46 -08001631XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001632{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001633 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001634
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 fseek( fp, 0, SEEK_END );
1636 size_t size = ftell( fp );
1637 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001638
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001640 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001641 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001643
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 _charBuffer = new char[size+1];
1645 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 if ( read != size ) {
1647 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001650
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001652
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 if ( !p || !*p ) {
1657 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001660
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1662 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001663}
1664
1665
Lee Thomason2fa81722012-11-09 12:37:46 -08001666XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001667{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 FILE* fp = 0;
1669#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1670 errno_t err = fopen_s(&fp, filename, "w" );
1671 if ( !fp || err) {
1672#else
1673 fp = fopen( filename, "w" );
1674 if ( !fp) {
1675#endif
1676 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 }
1679 SaveFile(fp, compact);
1680 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001682}
1683
1684
Lee Thomason2fa81722012-11-09 12:37:46 -08001685XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001686{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 XMLPrinter stream( fp, compact );
1688 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001690}
1691
Lee Thomason1ff38e02012-02-14 18:18:16 -08001692
Lee Thomason2fa81722012-11-09 12:37:46 -08001693XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001694{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001695 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001696 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001697
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 if ( !p || !*p ) {
1699 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 }
1702 if ( len == (size_t)(-1) ) {
1703 len = strlen( p );
1704 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 _charBuffer = new char[ len+1 ];
1706 memcpy( _charBuffer, p, len );
1707 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001708
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 if ( !p || !*p ) {
1712 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001713 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001715
Thomas Roß1470edc2013-05-10 15:44:12 +02001716 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001717 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001719}
1720
1721
PKEuS1c5f99e2013-07-06 11:28:39 +02001722void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001723{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 XMLPrinter stdStreamer( stdout );
1725 if ( !streamer ) {
1726 streamer = &stdStreamer;
1727 }
1728 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001729}
1730
1731
Lee Thomason2fa81722012-11-09 12:37:46 -08001732void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001733{
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 _errorID = error;
1735 _errorStr1 = str1;
1736 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001737}
1738
Lee Thomason5cae8972012-01-24 18:03:07 -08001739
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001740void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001741{
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 static const int LEN = 20;
1744 char buf1[LEN] = { 0 };
1745 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001746
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 if ( _errorStr1 ) {
1748 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 if ( _errorStr2 ) {
1751 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001753
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001757}
1758
1759
PKEuS1bfb9542013-08-04 13:51:17 +02001760XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 _elementJustOpened( false ),
1762 _firstElement( true ),
1763 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001764 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 _textDepth( -1 ),
1766 _processEntities( true ),
1767 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 _entityFlag[i] = false;
1771 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 }
1773 for( int i=0; i<NUM_ENTITIES; ++i ) {
1774 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1775 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001776 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 }
1778 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 _restrictedEntityFlag[(int)'&'] = true;
1780 _restrictedEntityFlag[(int)'<'] = true;
1781 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1782 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001783}
1784
1785
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001786void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001787{
1788 va_list va;
1789 va_start( va, format );
1790
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 if ( _fp ) {
1792 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 else {
1795 // This seems brutally complex. Haven't figured out a better
1796 // way on windows.
1797#ifdef _MSC_VER
1798 int len = -1;
1799 int expand = 1000;
1800 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 if ( len < 0 ) {
1803 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001804 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
1806 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001807 char* p = _buffer.PushArr( len ) - 1;
1808 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809#else
1810 int len = vsnprintf( 0, 0, format, va );
1811 // Close out and re-start the va-args
1812 va_end( va );
1813 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 vsnprintf( p, len+1, format, va );
1816#endif
1817 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001818 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001819}
1820
1821
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001822void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001823{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 for( int i=0; i<depth; ++i ) {
1825 Print( " " );
1826 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001827}
1828
1829
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001830void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001831{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 // Look for runs of bytes between entities to print.
1833 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001835
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 while ( *q ) {
1838 // Remember, char is sometimes signed. (How many times has that bitten me?)
1839 if ( *q > 0 && *q < ENTITY_RANGE ) {
1840 // Check for entities. If one is found, flush
1841 // the stream up until the entity, write the
1842 // entity, and keep looking.
1843 if ( flag[(unsigned)(*q)] ) {
1844 while ( p < q ) {
1845 Print( "%c", *p );
1846 ++p;
1847 }
1848 for( int i=0; i<NUM_ENTITIES; ++i ) {
1849 if ( entities[i].value == *q ) {
1850 Print( "&%s;", entities[i].pattern );
1851 break;
1852 }
1853 }
1854 ++p;
1855 }
1856 }
1857 ++q;
1858 }
1859 }
1860 // Flush the remaining string. This will be the entire
1861 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 Print( "%s", p );
1864 }
Lee Thomason857b8682012-01-25 17:50:25 -08001865}
1866
U-Stream\Leeae25a442012-02-17 17:48:16 -08001867
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001868void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001869{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001871 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 Print( "%s", bom );
1873 }
1874 if ( writeDec ) {
1875 PushDeclaration( "xml version=\"1.0\"" );
1876 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001877}
1878
1879
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001880void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001881{
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 SealElement();
1884 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001886
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001889 }
1890 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001893
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 _elementJustOpened = true;
1896 _firstElement = false;
1897 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001898}
1899
1900
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001901void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001902{
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 Print( " %s=\"", name );
1905 PrintString( value, false );
1906 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001907}
1908
1909
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001910void XMLPrinter::PushAttribute( const char* name, int v )
1911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 char buf[BUF_SIZE];
1913 XMLUtil::ToStr( v, buf, BUF_SIZE );
1914 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001915}
1916
1917
1918void XMLPrinter::PushAttribute( const char* name, unsigned v )
1919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 char buf[BUF_SIZE];
1921 XMLUtil::ToStr( v, buf, BUF_SIZE );
1922 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001923}
1924
1925
1926void XMLPrinter::PushAttribute( const char* name, bool v )
1927{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 char buf[BUF_SIZE];
1929 XMLUtil::ToStr( v, buf, BUF_SIZE );
1930 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001931}
1932
1933
1934void XMLPrinter::PushAttribute( const char* name, double v )
1935{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 char buf[BUF_SIZE];
1937 XMLUtil::ToStr( v, buf, BUF_SIZE );
1938 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001939}
1940
1941
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001942void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001943{
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 --_depth;
1945 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001946
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 Print( "/>" );
1949 }
1950 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 }
1955 Print( "</%s>", name );
1956 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001957
Lee Thomason624d43f2012-10-12 10:58:48 -07001958 if ( _textDepth == _depth ) {
1959 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 Print( "\n" );
1963 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001965}
1966
1967
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001968void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001969{
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001972}
1973
1974
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001975void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001976{
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001978
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 SealElement();
1981 }
1982 if ( cdata ) {
1983 Print( "<![CDATA[" );
1984 Print( "%s", text );
1985 Print( "]]>" );
1986 }
1987 else {
1988 PrintString( text, true );
1989 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001990}
1991
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001992void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 char buf[BUF_SIZE];
1995 XMLUtil::ToStr( value, buf, BUF_SIZE );
1996 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001997}
1998
1999
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002000void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002001{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 char buf[BUF_SIZE];
2003 XMLUtil::ToStr( value, buf, BUF_SIZE );
2004 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002005}
2006
2007
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002008void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 char buf[BUF_SIZE];
2011 XMLUtil::ToStr( value, buf, BUF_SIZE );
2012 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002013}
2014
2015
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002016void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 char buf[BUF_SIZE];
2019 XMLUtil::ToStr( value, buf, BUF_SIZE );
2020 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002021}
2022
2023
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002024void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 char buf[BUF_SIZE];
2027 XMLUtil::ToStr( value, buf, BUF_SIZE );
2028 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002029}
2030
Lee Thomason5cae8972012-01-24 18:03:07 -08002031
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002032void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -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-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002043}
Lee Thomason751da522012-02-10 08:50:51 -08002044
2045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002046void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002047{
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 SealElement();
2050 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002057}
2058
2059
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002060void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002061{
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 SealElement();
2064 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002065 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002071}
2072
2073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002075{
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 if ( doc.HasBOM() ) {
2078 PushHeader( true, false );
2079 }
2080 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002081}
2082
2083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 OpenElement( element.Name() );
2087 while ( attribute ) {
2088 PushAttribute( attribute->Name(), attribute->Value() );
2089 attribute = attribute->Next();
2090 }
2091 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002092}
2093
2094
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002095bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 CloseElement();
2098 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002099}
2100
2101
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002102bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 PushText( text.Value(), text.CData() );
2105 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002106}
2107
2108
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002109bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 PushComment( comment.Value() );
2112 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002113}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002114
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002115bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 PushDeclaration( declaration.Value() );
2118 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002119}
2120
2121
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002122bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 PushUnknown( unknown.Value() );
2125 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002126}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002127
Lee Thomason685b8952012-11-12 13:00:06 -08002128} // namespace tinyxml2
2129