blob: 1bf4fdae64374fda351b78fbf191342ee66e8c94 [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
33using namespace tinyxml2;
Jerome Martinez7fbefab2012-10-19 11:30:33 +020034using namespace std;
U-Lama\Lee560bd472011-12-28 19:42:49 -080035
Lee Thomasone4422302012-01-20 17:59:50 -080036static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080037static const char LF = LINE_FEED;
38static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
39static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080040static const char SINGLE_QUOTE = '\'';
41static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080042
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080043// Bunch of unicode info at:
44// http://www.unicode.org/faq/utf_bom.html
45// ef bb bf (Microsoft "lead bytes") - designates UTF-8
46
47static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
48static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
49static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080050
51
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080052#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070053 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070054 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070055 node->~XMLNode(); \
56 pool->Free( node ); \
57 } \
58 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080059#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070060 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070061 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070062 attrib->~XMLAttribute(); \
63 pool->Free( attrib ); \
64 } \
65 }
Lee Thomason43f59302012-02-06 18:18:11 -080066
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700139 while( *p && (
140 XMLUtil::IsAlphaNum( (unsigned char) *p )
141 || *p == '_'
142 || *p == ':'
143 || (*p == '-' && p>start ) // can be in a name, but not lead it.
144 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
145 ++p;
146 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800147
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700148 if ( p > start ) {
149 Set( start, p, 0 );
150 return p;
151 }
152 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800153}
154
155
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700156void StrPair::CollapseWhitespace()
157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700158 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700159 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700160
Lee Thomason120b3a62012-10-12 10:06:59 -0700161 if ( _start && *_start ) {
162 char* p = _start; // the read pointer
163 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700165 while( *p ) {
166 if ( XMLUtil::IsWhiteSpace( *p )) {
167 p = XMLUtil::SkipWhiteSpace( p );
168 if ( *p == 0 ) {
169 break; // don't write to q; this trims the trailing space.
170 }
171 *q = ' ';
172 ++q;
173 }
174 *q = *p;
175 ++q;
176 ++p;
177 }
178 *q = 0;
179 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700180}
181
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800182
Lee Thomasone4422302012-01-20 17:59:50 -0800183const char* StrPair::GetStr()
184{
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 if ( _flags & NEEDS_FLUSH ) {
186 *_end = 0;
187 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800188
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags ) {
190 char* p = _start; // the read pointer
191 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 while( p < _end ) {
194 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 // CR-LF pair becomes LF
196 // CR alone becomes LF
197 // LF-CR becomes LF
198 if ( *(p+1) == LF ) {
199 p += 2;
200 }
201 else {
202 ++p;
203 }
204 *q++ = LF;
205 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700206 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700207 if ( *(p+1) == CR ) {
208 p += 2;
209 }
210 else {
211 ++p;
212 }
213 *q++ = LF;
214 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700215 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 // Entities handled by tinyXML2:
217 // - special entities in the entity table [in/out]
218 // - numeric character reference [in]
219 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800220
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 if ( *(p+1) == '#' ) {
222 char buf[10] = { 0 };
223 int len;
224 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
225 for( int i=0; i<len; ++i ) {
226 *q++ = buf[i];
227 }
228 TIXMLASSERT( q <= p );
229 }
230 else {
231 int i=0;
232 for(; i<NUM_ENTITIES; ++i ) {
233 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
234 && *(p+entities[i].length+1) == ';' ) {
235 // Found an entity convert;
236 *q = entities[i].value;
237 ++q;
238 p += entities[i].length + 2;
239 break;
240 }
241 }
242 if ( i == NUM_ENTITIES ) {
243 // fixme: treat as error?
244 ++p;
245 ++q;
246 }
247 }
248 }
249 else {
250 *q = *p;
251 ++p;
252 ++q;
253 }
254 }
255 *q = 0;
256 }
257 // The loop below has plenty going on, and this
258 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 CollapseWhitespace();
261 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700262 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700263 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800265}
266
Lee Thomason2c85a712012-01-31 08:24:24 -0800267
Lee Thomasone4422302012-01-20 17:59:50 -0800268
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800269
Lee Thomason56bdd022012-02-09 18:16:58 -0800270// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800271
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800272const char* XMLUtil::ReadBOM( const char* p, bool* bom )
273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700274 *bom = false;
275 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
276 // Check for BOM:
277 if ( *(pu+0) == TIXML_UTF_LEAD_0
278 && *(pu+1) == TIXML_UTF_LEAD_1
279 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
280 *bom = true;
281 p += 3;
282 }
283 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800284}
285
286
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700289 const unsigned long BYTE_MASK = 0xBF;
290 const unsigned long BYTE_MARK = 0x80;
291 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800292
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if (input < 0x80) {
294 *length = 1;
295 }
296 else if ( input < 0x800 ) {
297 *length = 2;
298 }
299 else if ( input < 0x10000 ) {
300 *length = 3;
301 }
302 else if ( input < 0x200000 ) {
303 *length = 4;
304 }
305 else {
306 *length = 0; // This code won't covert this correctly anyway.
307 return;
308 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800309
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800311
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700312 // Scary scary fall throughs.
313 switch (*length) {
314 case 4:
315 --output;
316 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
317 input >>= 6;
318 case 3:
319 --output;
320 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
321 input >>= 6;
322 case 2:
323 --output;
324 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
325 input >>= 6;
326 case 1:
327 --output;
328 *output = (char)(input | FIRST_BYTE_MARK[*length]);
329 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800330}
331
332
333const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 // Presume an entity, and pull it out.
336 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800337
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 if ( *(p+1) == '#' && *(p+2) ) {
339 unsigned long ucs = 0;
340 ptrdiff_t delta = 0;
341 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 if ( *(p+2) == 'x' ) {
344 // Hexadecimal.
345 if ( !*(p+3) ) {
346 return 0;
347 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 const char* q = p+3;
350 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( !q || !*q ) {
353 return 0;
354 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 delta = q-p;
357 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 while ( *q != 'x' ) {
360 if ( *q >= '0' && *q <= '9' ) {
361 ucs += mult * (*q - '0');
362 }
363 else if ( *q >= 'a' && *q <= 'f' ) {
364 ucs += mult * (*q - 'a' + 10);
365 }
366 else if ( *q >= 'A' && *q <= 'F' ) {
367 ucs += mult * (*q - 'A' + 10 );
368 }
369 else {
370 return 0;
371 }
372 mult *= 16;
373 --q;
374 }
375 }
376 else {
377 // Decimal.
378 if ( !*(p+2) ) {
379 return 0;
380 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 const char* q = p+2;
383 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 if ( !q || !*q ) {
386 return 0;
387 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 delta = q-p;
390 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 while ( *q != '#' ) {
393 if ( *q >= '0' && *q <= '9' ) {
394 ucs += mult * (*q - '0');
395 }
396 else {
397 return 0;
398 }
399 mult *= 10;
400 --q;
401 }
402 }
403 // convert the UCS to UTF-8
404 ConvertUTF32ToUTF8( ucs, value, length );
405 return p + delta + 1;
406 }
407 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800409
410
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700411void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700413 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700414}
415
416
417void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700420}
421
422
423void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700426}
427
428
429void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700432}
433
434
435void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441bool XMLUtil::ToInt( const char* str, int* value )
442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
444 return true;
445 }
446 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
449bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
452 return true;
453 }
454 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457bool XMLUtil::ToBool( const char* str, bool* value )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 int ival = 0;
460 if ( ToInt( str, &ival )) {
461 *value = (ival==0) ? false : true;
462 return true;
463 }
464 if ( StringEqual( str, "true" ) ) {
465 *value = true;
466 return true;
467 }
468 else if ( StringEqual( str, "false" ) ) {
469 *value = false;
470 return true;
471 }
472 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700473}
474
475
476bool XMLUtil::ToFloat( const char* str, float* value )
477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
479 return true;
480 }
481 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484bool XMLUtil::ToDouble( const char* str, double* value )
485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700493char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 XMLNode* returnNode = 0;
496 char* start = p;
497 p = XMLUtil::SkipWhiteSpace( p );
498 if( !p || !*p ) {
499 return p;
500 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 // What is this thing?
503 // - Elements start with a letter or underscore, but xml is reserved.
504 // - Comments: <!--
505 // - Decleration: <?
506 // - Everthing else is unknown to tinyxml.
507 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 static const char* xmlHeader = { "<?" };
510 static const char* commentHeader = { "<!--" };
511 static const char* dtdHeader = { "<!" };
512 static const char* cdataHeader = { "<![CDATA[" };
513 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 static const int xmlHeaderLen = 2;
516 static const int commentHeaderLen = 4;
517 static const int dtdHeaderLen = 2;
518 static const int cdataHeaderLen = 9;
519 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800520
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800521#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800522#pragma warning ( push )
523#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
526 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800527#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800528#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
532 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 p += xmlHeaderLen;
534 }
535 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700536 returnNode = new (_commentPool.Alloc()) XMLComment( this );
537 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 p += commentHeaderLen;
539 }
540 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700541 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += cdataHeaderLen;
545 text->SetCData( true );
546 }
547 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
549 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += dtdHeaderLen;
551 }
552 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 returnNode = new (_elementPool.Alloc()) XMLElement( this );
554 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p += elementHeaderLen;
556 }
557 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_textPool.Alloc()) XMLText( this );
559 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p = start; // Back it up, all the text counts.
561 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 *node = returnNode;
564 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800565}
566
567
Lee Thomason751da522012-02-10 08:50:51 -0800568bool XMLDocument::Accept( XMLVisitor* visitor ) const
569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 if ( visitor->VisitEnter( *this ) ) {
571 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
572 if ( !node->Accept( visitor ) ) {
573 break;
574 }
575 }
576 }
577 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800578}
Lee Thomason56bdd022012-02-09 18:16:58 -0800579
580
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800581// --------- XMLNode ----------- //
582
583XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700584 _document( doc ),
585 _parent( 0 ),
586 _firstChild( 0 ), _lastChild( 0 ),
587 _prev( 0 ), _next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800589}
590
591
592XMLNode::~XMLNode()
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 if ( _parent ) {
596 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800598}
599
600
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800601void XMLNode::SetValue( const char* str, bool staticMem )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 }
606 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800609}
610
611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800612void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613{
Lee Thomason624d43f2012-10-12 10:58:48 -0700614 while( _firstChild ) {
615 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700617
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 DELETE_NODE( node );
619 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800621}
622
623
624void XMLNode::Unlink( XMLNode* child )
625{
Lee Thomason624d43f2012-10-12 10:58:48 -0700626 TIXMLASSERT( child->_parent == this );
627 if ( child == _firstChild ) {
628 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 if ( child == _lastChild ) {
631 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 }
Lee Thomasond923c672012-01-23 08:44:25 -0800633
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 if ( child->_prev ) {
635 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child->_next ) {
638 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641}
642
643
U-Stream\Leeae25a442012-02-17 17:48:16 -0800644void XMLNode::DeleteChild( XMLNode* node )
645{
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800648}
649
650
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652{
Lee Thomason624d43f2012-10-12 10:58:48 -0700653 if ( _lastChild ) {
654 TIXMLASSERT( _firstChild );
655 TIXMLASSERT( _lastChild->_next == 0 );
656 _lastChild->_next = addThis;
657 addThis->_prev = _lastChild;
658 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
662 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 TIXMLASSERT( _firstChild == 0 );
664 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665
Lee Thomason624d43f2012-10-12 10:58:48 -0700666 addThis->_prev = 0;
667 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671}
672
673
Lee Thomason1ff38e02012-02-14 18:18:16 -0800674XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
675{
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 if ( _firstChild ) {
677 TIXMLASSERT( _lastChild );
678 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800679
Lee Thomason624d43f2012-10-12 10:58:48 -0700680 _firstChild->_prev = addThis;
681 addThis->_next = _firstChild;
682 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800683
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 }
686 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 TIXMLASSERT( _lastChild == 0 );
688 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_prev = 0;
691 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695}
696
697
698XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
699{
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 TIXMLASSERT( afterThis->_parent == this );
701 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 return 0;
703 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 // The last node or the only node.
707 return InsertEndChild( addThis );
708 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 addThis->_prev = afterThis;
710 addThis->_next = afterThis->_next;
711 afterThis->_next->_prev = addThis;
712 afterThis->_next = addThis;
713 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800715}
716
717
718
719
Lee Thomason56bdd022012-02-09 18:16:58 -0800720const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800721{
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 XMLElement* element = node->ToElement();
724 if ( element ) {
725 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
726 return element;
727 }
728 }
729 }
730 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800731}
732
733
Lee Thomason56bdd022012-02-09 18:16:58 -0800734const XMLElement* XMLNode::LastChildElement( const char* value ) const
735{
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 XMLElement* element = node->ToElement();
738 if ( element ) {
739 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
740 return element;
741 }
742 }
743 }
744 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800745}
746
747
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800748const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
749{
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 if ( element->ToElement()
752 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
753 return element->ToElement();
754 }
755 }
756 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800757}
758
759
760const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
761{
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 if ( element->ToElement()
764 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
765 return element->ToElement();
766 }
767 }
768 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800769}
770
771
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800772char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800773{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 // This is a recursive method, but thinking about it "at the current level"
775 // it is a pretty simple flat list:
776 // <foo/>
777 // <!-- comment -->
778 //
779 // With a special case:
780 // <foo>
781 // </foo>
782 // <!-- comment -->
783 //
784 // Where the closing element (/foo) *must* be the next thing after the opening
785 // element, and the names must match. BUT the tricky bit is that the closing
786 // element will be read by the child.
787 //
788 // 'endTag' is the end tag for this node, it is returned by a call to a child.
789 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800790
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700791 while( p && *p ) {
792 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800793
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 if ( p == 0 || node == 0 ) {
796 break;
797 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800798
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 StrPair endTag;
800 p = node->ParseDeep( p, &endTag );
801 if ( !p ) {
802 DELETE_NODE( node );
803 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700804 if ( !_document->Error() ) {
805 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
807 break;
808 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800809
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 // We read the end tag. Return it to the parent.
811 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
812 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700813 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
815 DELETE_NODE( node );
816 return p;
817 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800818
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 // Handle an end tag returned to this level.
820 // And handle a bunch of annoying errors.
821 XMLElement* ele = node->ToElement();
822 if ( ele ) {
823 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 p = 0;
826 }
827 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 p = 0;
830 }
831 else if ( !endTag.Empty() ) {
832 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700833 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 p = 0;
835 }
836 }
837 }
838 if ( p == 0 ) {
839 DELETE_NODE( node );
840 node = 0;
841 }
842 if ( node ) {
843 this->InsertEndChild( node );
844 }
845 }
846 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800847}
848
Lee Thomason5492a1c2012-01-23 15:32:10 -0800849// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800850char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800851{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 const char* start = p;
853 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 return p;
859 }
860 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
862 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 flags |= StrPair::COLLAPSE_WHITESPACE;
864 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700865
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 }
870 if ( p && *p ) {
871 return p-1;
872 }
873 }
874 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800875}
876
877
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800878XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
879{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
884 text->SetCData( this->CData() );
885 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800886}
887
888
889bool XMLText::ShallowEqual( const XMLNode* compare ) const
890{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800892}
893
894
Lee Thomason56bdd022012-02-09 18:16:58 -0800895bool XMLText::Accept( XMLVisitor* visitor ) const
896{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800898}
899
900
Lee Thomason3f57d272012-01-11 15:30:03 -0800901// --------- XMLComment ---------- //
902
Lee Thomasone4422302012-01-20 17:59:50 -0800903XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800904{
905}
906
907
Lee Thomasonce0763e2012-01-11 15:43:54 -0800908XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800909{
Lee Thomason3f57d272012-01-11 15:30:03 -0800910}
911
912
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 // Comment parses as text.
916 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800922}
923
924
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800925XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
926{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 }
930 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
931 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800932}
933
934
935bool XMLComment::ShallowEqual( const XMLNode* compare ) const
936{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938}
939
940
Lee Thomason751da522012-02-10 08:50:51 -0800941bool XMLComment::Accept( XMLVisitor* visitor ) const
942{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800944}
Lee Thomason56bdd022012-02-09 18:16:58 -0800945
946
Lee Thomason50f97b22012-02-11 16:33:40 -0800947// --------- XMLDeclaration ---------- //
948
949XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
950{
951}
952
953
954XMLDeclaration::~XMLDeclaration()
955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800957}
958
959
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800960char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 // Declaration parses as text.
963 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700964 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700966 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 }
968 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800969}
970
971
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700975 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 }
977 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
978 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800979}
980
981
982bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
988
Lee Thomason50f97b22012-02-11 16:33:40 -0800989bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
990{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800992}
993
994// --------- XMLUnknown ---------- //
995
996XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
997{
998}
999
1000
1001XMLUnknown::~XMLUnknown()
1002{
1003}
1004
1005
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001006char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 // Unknown parses as text.
1009 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001010
Lee Thomason624d43f2012-10-12 10:58:48 -07001011 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001013 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 }
1015 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001016}
1017
1018
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001019XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1020{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001022 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1025 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001026}
1027
1028
1029bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1030{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001032}
1033
1034
Lee Thomason50f97b22012-02-11 16:33:40 -08001035bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001038}
1039
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001040// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001041char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 if ( !p || !*p ) {
1046 return 0;
1047 }
Lee Thomason22aead12012-01-23 13:29:35 -08001048
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 // Skip white space before =
1050 p = XMLUtil::SkipWhiteSpace( p );
1051 if ( !p || *p != '=' ) {
1052 return 0;
1053 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001054
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 ++p; // move up to opening quote
1056 p = XMLUtil::SkipWhiteSpace( p );
1057 if ( *p != '\"' && *p != '\'' ) {
1058 return 0;
1059 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001060
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 char endTag[2] = { *p, 0 };
1062 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001063
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066}
1067
1068
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001069void XMLAttribute::SetName( const char* n )
1070{
Lee Thomason624d43f2012-10-12 10:58:48 -07001071 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001072}
1073
1074
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001075int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 if ( XMLUtil::ToInt( Value(), value )) {
1078 return XML_NO_ERROR;
1079 }
1080 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001081}
1082
1083
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001084int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( XMLUtil::ToUnsigned( Value(), value )) {
1087 return XML_NO_ERROR;
1088 }
1089 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001090}
1091
1092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 if ( XMLUtil::ToBool( Value(), value )) {
1096 return XML_NO_ERROR;
1097 }
1098 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001099}
1100
1101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 if ( XMLUtil::ToFloat( Value(), value )) {
1105 return XML_NO_ERROR;
1106 }
1107 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001108}
1109
1110
1111int XMLAttribute::QueryDoubleValue( double* value ) const
1112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( XMLUtil::ToDouble( Value(), value )) {
1114 return XML_NO_ERROR;
1115 }
1116 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117}
1118
1119
1120void XMLAttribute::SetAttribute( const char* v )
1121{
Lee Thomason624d43f2012-10-12 10:58:48 -07001122 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001123}
1124
1125
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126void XMLAttribute::SetAttribute( int v )
1127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 char buf[BUF_SIZE];
1129 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001130 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001132
1133
1134void XMLAttribute::SetAttribute( unsigned v )
1135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 char buf[BUF_SIZE];
1137 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001139}
1140
1141
1142void XMLAttribute::SetAttribute( bool v )
1143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 char buf[BUF_SIZE];
1145 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001146 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001147}
1148
1149void XMLAttribute::SetAttribute( double v )
1150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 char buf[BUF_SIZE];
1152 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001154}
1155
1156void XMLAttribute::SetAttribute( float 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 Thomason1a1d4a72012-02-15 09:09:25 -08001161}
1162
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001163
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001164// --------- XMLElement ---------- //
1165XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 _closingType( 0 ),
1167 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001168{
1169}
1170
1171
1172XMLElement::~XMLElement()
1173{
Lee Thomason624d43f2012-10-12 10:58:48 -07001174 while( _rootAttribute ) {
1175 XMLAttribute* next = _rootAttribute->_next;
1176 DELETE_ATTRIBUTE( _rootAttribute );
1177 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001179}
1180
1181
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001182XMLAttribute* XMLElement::FindAttribute( const char* name )
1183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001185 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1187 return a;
1188 }
1189 }
1190 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193
1194const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1199 return a;
1200 }
1201 }
1202 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001203}
1204
1205
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001206const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 const XMLAttribute* a = FindAttribute( name );
1209 if ( !a ) {
1210 return 0;
1211 }
1212 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1213 return a->Value();
1214 }
1215 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001216}
1217
1218
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001219const char* XMLElement::GetText() const
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 if ( FirstChild() && FirstChild()->ToText() ) {
1222 return FirstChild()->ToText()->Value();
1223 }
1224 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001225}
1226
1227
Lee Thomason21be8822012-07-15 17:27:22 -07001228int XMLElement::QueryIntText( int* _value ) const
1229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 if ( FirstChild() && FirstChild()->ToText() ) {
1231 const char* t = FirstChild()->ToText()->Value();
1232 if ( XMLUtil::ToInt( t, _value ) ) {
1233 return XML_SUCCESS;
1234 }
1235 return XML_CAN_NOT_CONVERT_TEXT;
1236 }
1237 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001238}
1239
1240
1241int XMLElement::QueryUnsignedText( unsigned* _value ) const
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 if ( FirstChild() && FirstChild()->ToText() ) {
1244 const char* t = FirstChild()->ToText()->Value();
1245 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1246 return XML_SUCCESS;
1247 }
1248 return XML_CAN_NOT_CONVERT_TEXT;
1249 }
1250 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001251}
1252
1253
1254int XMLElement::QueryBoolText( bool* _value ) const
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 const char* t = FirstChild()->ToText()->Value();
1258 if ( XMLUtil::ToBool( t, _value ) ) {
1259 return XML_SUCCESS;
1260 }
1261 return XML_CAN_NOT_CONVERT_TEXT;
1262 }
1263 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001264}
1265
1266
1267int XMLElement::QueryDoubleText( double* _value ) const
1268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 if ( FirstChild() && FirstChild()->ToText() ) {
1270 const char* t = FirstChild()->ToText()->Value();
1271 if ( XMLUtil::ToDouble( t, _value ) ) {
1272 return XML_SUCCESS;
1273 }
1274 return XML_CAN_NOT_CONVERT_TEXT;
1275 }
1276 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001277}
1278
1279
1280int XMLElement::QueryFloatText( float* _value ) const
1281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 if ( FirstChild() && FirstChild()->ToText() ) {
1283 const char* t = FirstChild()->ToText()->Value();
1284 if ( XMLUtil::ToFloat( t, _value ) ) {
1285 return XML_SUCCESS;
1286 }
1287 return XML_CAN_NOT_CONVERT_TEXT;
1288 }
1289 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001290}
1291
1292
1293
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001294XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 XMLAttribute* last = 0;
1297 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001300 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1302 break;
1303 }
1304 }
1305 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001306 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1307 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001309 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 }
1311 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 }
1314 attrib->SetName( name );
1315 }
1316 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001317}
1318
1319
U-Stream\Leeae25a442012-02-17 17:48:16 -08001320void XMLElement::DeleteAttribute( const char* name )
1321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001323 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1325 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001326 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 }
1328 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001329 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 DELETE_ATTRIBUTE( a );
1332 break;
1333 }
1334 prev = a;
1335 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001336}
1337
1338
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001339char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 const char* start = p;
1342 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001343
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 // Read the attributes.
1345 while( p ) {
1346 p = XMLUtil::SkipWhiteSpace( p );
1347 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001348 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 return 0;
1350 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 // attribute.
1353 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001354 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1355 attrib->_memPool = &_document->_attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001356
Lee Thomason624d43f2012-10-12 10:58:48 -07001357 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( !p || Attribute( attrib->Name() ) ) {
1359 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001360 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return 0;
1362 }
1363 // There is a minor bug here: if the attribute in the source xml
1364 // document is duplicated, it will not be detected and the
1365 // attribute will be doubly added. However, tracking the 'prevAttribute'
1366 // avoids re-scanning the attribute list. Preferring performance for
1367 // now, may reconsider in the future.
1368 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 }
1371 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 }
1374 prevAttribute = attrib;
1375 }
1376 // end of the tag
1377 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001378 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return p+2; // done; sealed element.
1380 }
1381 // end of the tag
1382 else if ( *p == '>' ) {
1383 ++p;
1384 break;
1385 }
1386 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001387 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 return 0;
1389 }
1390 }
1391 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001392}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001393
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001394
Lee Thomason67d61312012-01-24 16:01:51 -08001395//
1396// <ele></ele>
1397// <ele>foo<b>bar</b></ele>
1398//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001399char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 // Read the element name.
1402 p = XMLUtil::SkipWhiteSpace( p );
1403 if ( !p ) {
1404 return 0;
1405 }
Lee Thomason67d61312012-01-24 16:01:51 -08001406
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 // The closing element is the </element> form. It is
1408 // parsed just like a regular element then deleted from
1409 // the DOM.
1410 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001411 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 ++p;
1413 }
Lee Thomason67d61312012-01-24 16:01:51 -08001414
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 p = _value.ParseName( p );
1416 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 return 0;
1418 }
Lee Thomason67d61312012-01-24 16:01:51 -08001419
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 return p;
1423 }
Lee Thomason67d61312012-01-24 16:01:51 -08001424
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 p = XMLNode::ParseDeep( p, strPair );
1426 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427}
1428
1429
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001430
1431XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 }
1436 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1437 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1438 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1439 }
1440 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001441}
1442
1443
1444bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 const XMLElement* other = compare->ToElement();
1447 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001448
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 const XMLAttribute* a=FirstAttribute();
1450 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001451
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 while ( a && b ) {
1453 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1454 return false;
1455 }
1456 a = a->Next();
1457 b = b->Next();
1458 }
1459 if ( a || b ) {
1460 // different count
1461 return false;
1462 }
1463 return true;
1464 }
1465 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001466}
1467
1468
Lee Thomason751da522012-02-10 08:50:51 -08001469bool XMLElement::Accept( XMLVisitor* visitor ) const
1470{
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1473 if ( !node->Accept( visitor ) ) {
1474 break;
1475 }
1476 }
1477 }
1478 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001479}
Lee Thomason56bdd022012-02-09 18:16:58 -08001480
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001481
Lee Thomason3f57d272012-01-11 15:30:03 -08001482// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001483XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 _writeBOM( false ),
1486 _processEntities( processEntities ),
1487 _errorID( 0 ),
1488 _whitespace( whitespace ),
1489 _errorStr1( 0 ),
1490 _errorStr2( 0 ),
1491 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001492{
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001494}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001495
1496
Lee Thomason3f57d272012-01-11 15:30:03 -08001497XMLDocument::~XMLDocument()
1498{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001501
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001502#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 textPool.Trace( "text" );
1504 elementPool.Trace( "element" );
1505 commentPool.Trace( "comment" );
1506 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001507#endif
1508
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 TIXMLASSERT( _textPool.CurrentAllocs() == 0 );
1510 TIXMLASSERT( _elementPool.CurrentAllocs() == 0 );
1511 TIXMLASSERT( _commentPool.CurrentAllocs() == 0 );
1512 TIXMLASSERT( _attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001513}
1514
1515
Lee Thomason18d68bd2012-01-26 18:17:26 -08001516void XMLDocument::InitDocument()
1517{
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 _errorID = XML_NO_ERROR;
1519 _errorStr1 = 0;
1520 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001521
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 delete [] _charBuffer;
1523 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001524}
1525
Lee Thomason3f57d272012-01-11 15:30:03 -08001526
Lee Thomason2c85a712012-01-31 08:24:24 -08001527XMLElement* XMLDocument::NewElement( const char* name )
1528{
Lee Thomason624d43f2012-10-12 10:58:48 -07001529 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1530 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 ele->SetName( name );
1532 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001533}
1534
1535
Lee Thomason1ff38e02012-02-14 18:18:16 -08001536XMLComment* XMLDocument::NewComment( const char* str )
1537{
Lee Thomason624d43f2012-10-12 10:58:48 -07001538 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1539 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 comment->SetValue( str );
1541 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001542}
1543
1544
1545XMLText* XMLDocument::NewText( const char* str )
1546{
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1548 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 text->SetValue( str );
1550 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001551}
1552
1553
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001554XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1555{
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1557 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1559 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001560}
1561
1562
1563XMLUnknown* XMLDocument::NewUnknown( const char* str )
1564{
Lee Thomason624d43f2012-10-12 10:58:48 -07001565 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1566 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 unk->SetValue( str );
1568 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569}
1570
1571
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001572int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 DeleteChildren();
1575 InitDocument();
1576 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001577
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1579 errno_t err = fopen_s(&fp, filename, "rb" );
1580 if ( !fp || err) {
1581#else
1582 fp = fopen( filename, "rb" );
1583 if ( !fp) {
1584#endif
1585 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001586 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 }
1588 LoadFile( fp );
1589 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001591}
1592
1593
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001594int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 DeleteChildren();
1597 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001598
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 fseek( fp, 0, SEEK_END );
1600 size_t size = ftell( fp );
1601 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001602
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 if ( size == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001606
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 _charBuffer = new char[size+1];
1608 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 if ( read != size ) {
1610 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001612 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001613
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001615
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 if ( !p || !*p ) {
1620 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001621 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001623
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1625 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001626}
1627
1628
Robert Reif312a20f2012-09-08 19:33:57 -04001629int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001630{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 FILE* fp = 0;
1632#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1633 errno_t err = fopen_s(&fp, filename, "w" );
1634 if ( !fp || err) {
1635#else
1636 fp = fopen( filename, "w" );
1637 if ( !fp) {
1638#endif
1639 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 }
1642 SaveFile(fp, compact);
1643 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001645}
1646
1647
Robert Reif312a20f2012-09-08 19:33:57 -04001648int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 XMLPrinter stream( fp, compact );
1651 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001653}
1654
Lee Thomason1ff38e02012-02-14 18:18:16 -08001655
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001656int XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001657{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 DeleteChildren();
1659 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001660
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 if ( !p || !*p ) {
1662 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001663 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 }
1665 if ( len == (size_t)(-1) ) {
1666 len = strlen( p );
1667 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _charBuffer = new char[ len+1 ];
1669 memcpy( _charBuffer, p, len );
1670 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001671
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 if ( !p || !*p ) {
1675 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001677 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001678
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 ParseDeep( _charBuffer, 0 );
1680 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001681}
1682
1683
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001684void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001685{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 XMLPrinter stdStreamer( stdout );
1687 if ( !streamer ) {
1688 streamer = &stdStreamer;
1689 }
1690 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001691}
1692
1693
Lee Thomason67d61312012-01-24 16:01:51 -08001694void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1695{
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 _errorID = error;
1697 _errorStr1 = str1;
1698 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001699}
1700
Lee Thomason5cae8972012-01-24 18:03:07 -08001701
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001702void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001703{
Lee Thomason624d43f2012-10-12 10:58:48 -07001704 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 static const int LEN = 20;
1706 char buf1[LEN] = { 0 };
1707 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001708
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 if ( _errorStr1 ) {
1710 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001712 if ( _errorStr2 ) {
1713 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001715
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001719}
1720
1721
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001722XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 _elementJustOpened( false ),
1724 _firstElement( true ),
1725 _fp( file ),
1726 _depth( 0 ),
1727 _textDepth( -1 ),
1728 _processEntities( true ),
1729 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001730{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 _entityFlag[i] = false;
1733 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 }
1735 for( int i=0; i<NUM_ENTITIES; ++i ) {
1736 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1737 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 }
1740 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 _restrictedEntityFlag[(int)'&'] = true;
1742 _restrictedEntityFlag[(int)'<'] = true;
1743 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1744 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001745}
1746
1747
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001748void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001749{
1750 va_list va;
1751 va_start( va, format );
1752
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 if ( _fp ) {
1754 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 }
1756 else {
1757 // This seems brutally complex. Haven't figured out a better
1758 // way on windows.
1759#ifdef _MSC_VER
1760 int len = -1;
1761 int expand = 1000;
1762 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 if ( len < 0 ) {
1765 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001766 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 char* p = _buffer.PushArr( len ) - 1;
1770 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771#else
1772 int len = vsnprintf( 0, 0, format, va );
1773 // Close out and re-start the va-args
1774 va_end( va );
1775 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001776 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 vsnprintf( p, len+1, format, va );
1778#endif
1779 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001780 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001781}
1782
1783
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001784void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 for( int i=0; i<depth; ++i ) {
1787 Print( " " );
1788 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001789}
1790
1791
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001792void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001793{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 // Look for runs of bytes between entities to print.
1795 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001797
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 while ( *q ) {
1800 // Remember, char is sometimes signed. (How many times has that bitten me?)
1801 if ( *q > 0 && *q < ENTITY_RANGE ) {
1802 // Check for entities. If one is found, flush
1803 // the stream up until the entity, write the
1804 // entity, and keep looking.
1805 if ( flag[(unsigned)(*q)] ) {
1806 while ( p < q ) {
1807 Print( "%c", *p );
1808 ++p;
1809 }
1810 for( int i=0; i<NUM_ENTITIES; ++i ) {
1811 if ( entities[i].value == *q ) {
1812 Print( "&%s;", entities[i].pattern );
1813 break;
1814 }
1815 }
1816 ++p;
1817 }
1818 }
1819 ++q;
1820 }
1821 }
1822 // Flush the remaining string. This will be the entire
1823 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 Print( "%s", p );
1826 }
Lee Thomason857b8682012-01-25 17:50:25 -08001827}
1828
U-Stream\Leeae25a442012-02-17 17:48:16 -08001829
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001830void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001831{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1833 if ( writeBOM ) {
1834 Print( "%s", bom );
1835 }
1836 if ( writeDec ) {
1837 PushDeclaration( "xml version=\"1.0\"" );
1838 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001839}
1840
1841
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001842void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001843{
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 SealElement();
1846 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001848
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001853
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 _elementJustOpened = true;
1856 _firstElement = false;
1857 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001858}
1859
1860
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001861void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001862{
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 Print( " %s=\"", name );
1865 PrintString( value, false );
1866 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001867}
1868
1869
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001870void XMLPrinter::PushAttribute( const char* name, int v )
1871{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 char buf[BUF_SIZE];
1873 XMLUtil::ToStr( v, buf, BUF_SIZE );
1874 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001875}
1876
1877
1878void XMLPrinter::PushAttribute( const char* name, unsigned v )
1879{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 char buf[BUF_SIZE];
1881 XMLUtil::ToStr( v, buf, BUF_SIZE );
1882 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001883}
1884
1885
1886void XMLPrinter::PushAttribute( const char* name, bool v )
1887{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 char buf[BUF_SIZE];
1889 XMLUtil::ToStr( v, buf, BUF_SIZE );
1890 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001891}
1892
1893
1894void XMLPrinter::PushAttribute( const char* name, double v )
1895{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 char buf[BUF_SIZE];
1897 XMLUtil::ToStr( v, buf, BUF_SIZE );
1898 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001899}
1900
1901
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001902void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001903{
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 --_depth;
1905 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001906
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 Print( "/>" );
1909 }
1910 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 }
1915 Print( "</%s>", name );
1916 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001917
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 if ( _textDepth == _depth ) {
1919 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 Print( "\n" );
1923 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001925}
1926
1927
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001928void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001929{
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001932}
1933
1934
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001935void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001936{
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001938
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 SealElement();
1941 }
1942 if ( cdata ) {
1943 Print( "<![CDATA[" );
1944 Print( "%s", text );
1945 Print( "]]>" );
1946 }
1947 else {
1948 PrintString( text, true );
1949 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001950}
1951
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001952void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 char buf[BUF_SIZE];
1955 XMLUtil::ToStr( value, buf, BUF_SIZE );
1956 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001957}
1958
1959
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001960void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 char buf[BUF_SIZE];
1963 XMLUtil::ToStr( value, buf, BUF_SIZE );
1964 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001965}
1966
1967
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001968void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 char buf[BUF_SIZE];
1971 XMLUtil::ToStr( value, buf, BUF_SIZE );
1972 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001973}
1974
1975
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001976void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001977{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 char buf[BUF_SIZE];
1979 XMLUtil::ToStr( value, buf, BUF_SIZE );
1980 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001981}
1982
1983
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001984void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 char buf[BUF_SIZE];
1987 XMLUtil::ToStr( value, buf, BUF_SIZE );
1988 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001989}
1990
Lee Thomason5cae8972012-01-24 18:03:07 -08001991
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001992void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001993{
Lee Thomason624d43f2012-10-12 10:58:48 -07001994 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 SealElement();
1996 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002003}
Lee Thomason751da522012-02-10 08:50:51 -08002004
2005
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002006void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002007{
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 SealElement();
2010 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002015 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002017}
2018
2019
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002020void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002021{
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 SealElement();
2024 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002031}
2032
2033
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002034bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002035{
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 if ( doc.HasBOM() ) {
2038 PushHeader( true, false );
2039 }
2040 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002041}
2042
2043
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002044bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 OpenElement( element.Name() );
2047 while ( attribute ) {
2048 PushAttribute( attribute->Name(), attribute->Value() );
2049 attribute = attribute->Next();
2050 }
2051 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002052}
2053
2054
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002055bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002056{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 CloseElement();
2058 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002059}
2060
2061
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002062bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002063{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 PushText( text.Value(), text.CData() );
2065 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002066}
2067
2068
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002069bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 PushComment( comment.Value() );
2072 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002073}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002074
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002075bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 PushDeclaration( declaration.Value() );
2078 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002079}
2080
2081
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002082bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 PushUnknown( unknown.Value() );
2085 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086}