blob: 2536414730978f396033c3b64c8503bc5f192b2a [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;
34
Lee Thomasone4422302012-01-20 17:59:50 -080035static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080036static const char LF = LINE_FEED;
37static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
38static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080039static const char SINGLE_QUOTE = '\'';
40static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080041
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080042// Bunch of unicode info at:
43// http://www.unicode.org/faq/utf_bom.html
44// ef bb bf (Microsoft "lead bytes") - designates UTF-8
45
46static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
47static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
48static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080049
50
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080051#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070053 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070054 node->~XMLNode(); \
55 pool->Free( node ); \
56 } \
57 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080058#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070060 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070061 attrib->~XMLAttribute(); \
62 pool->Free( attrib ); \
63 } \
64 }
Lee Thomason43f59302012-02-06 18:18:11 -080065
Lee Thomason8ee79892012-01-25 17:44:30 -080066struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070067 const char* pattern;
68 int length;
69 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080070};
71
72static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070073static const Entity entities[NUM_ENTITIES] = {
74 { "quot", 4, DOUBLE_QUOTE },
75 { "amp", 3, '&' },
76 { "apos", 4, SINGLE_QUOTE },
77 { "lt", 2, '<' },
78 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080079};
80
Lee Thomasonfde6a752012-01-14 18:08:12 -080081
Lee Thomason1a1d4a72012-02-15 09:09:25 -080082StrPair::~StrPair()
83{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070084 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085}
86
87
88void StrPair::Reset()
89{
Lee Thomason120b3a62012-10-12 10:06:59 -070090 if ( _flags & NEEDS_DELETE ) {
91 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070092 }
Lee Thomason120b3a62012-10-12 10:06:59 -070093 _flags = 0;
94 _start = 0;
95 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096}
97
98
99void StrPair::SetStr( const char* str, int flags )
100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700101 Reset();
102 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700103 _start = new char[ len+1 ];
104 memcpy( _start, str, len+1 );
105 _end = _start + len;
106 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800107}
108
109
110char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700112 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800113
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700114 char* start = p; // fixme: hides a member
115 char endChar = *endTag;
116 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800117
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700118 // Inner loop of text parsing.
119 while ( *p ) {
120 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
121 Set( start, p, strFlags );
122 return p + length;
123 }
124 ++p;
125 }
126 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800127}
128
129
130char* StrPair::ParseName( char* p )
131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700132 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800133
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700134 if ( !start || !(*start) ) {
135 return 0;
136 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700138 while( *p && (
139 XMLUtil::IsAlphaNum( (unsigned char) *p )
140 || *p == '_'
141 || *p == ':'
142 || (*p == '-' && p>start ) // can be in a name, but not lead it.
143 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
144 ++p;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 if ( p > start ) {
148 Set( start, p, 0 );
149 return p;
150 }
151 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152}
153
154
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155void StrPair::CollapseWhitespace()
156{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700157 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700158 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomason120b3a62012-10-12 10:06:59 -0700160 if ( _start && *_start ) {
161 char* p = _start; // the read pointer
162 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700163
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700164 while( *p ) {
165 if ( XMLUtil::IsWhiteSpace( *p )) {
166 p = XMLUtil::SkipWhiteSpace( p );
167 if ( *p == 0 ) {
168 break; // don't write to q; this trims the trailing space.
169 }
170 *q = ' ';
171 ++q;
172 }
173 *q = *p;
174 ++q;
175 ++p;
176 }
177 *q = 0;
178 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700179}
180
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800181
Lee Thomasone4422302012-01-20 17:59:50 -0800182const char* StrPair::GetStr()
183{
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags & NEEDS_FLUSH ) {
185 *_end = 0;
186 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 if ( _flags ) {
189 char* p = _start; // the read pointer
190 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800191
Lee Thomason120b3a62012-10-12 10:06:59 -0700192 while( p < _end ) {
193 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 // CR-LF pair becomes LF
195 // CR alone becomes LF
196 // LF-CR becomes LF
197 if ( *(p+1) == LF ) {
198 p += 2;
199 }
200 else {
201 ++p;
202 }
203 *q++ = LF;
204 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700205 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 if ( *(p+1) == CR ) {
207 p += 2;
208 }
209 else {
210 ++p;
211 }
212 *q++ = LF;
213 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700214 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 // Entities handled by tinyXML2:
216 // - special entities in the entity table [in/out]
217 // - numeric character reference [in]
218 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800219
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 if ( *(p+1) == '#' ) {
221 char buf[10] = { 0 };
222 int len;
223 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
224 for( int i=0; i<len; ++i ) {
225 *q++ = buf[i];
226 }
227 TIXMLASSERT( q <= p );
228 }
229 else {
230 int i=0;
231 for(; i<NUM_ENTITIES; ++i ) {
232 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
233 && *(p+entities[i].length+1) == ';' ) {
234 // Found an entity convert;
235 *q = entities[i].value;
236 ++q;
237 p += entities[i].length + 2;
238 break;
239 }
240 }
241 if ( i == NUM_ENTITIES ) {
242 // fixme: treat as error?
243 ++p;
244 ++q;
245 }
246 }
247 }
248 else {
249 *q = *p;
250 ++p;
251 ++q;
252 }
253 }
254 *q = 0;
255 }
256 // The loop below has plenty going on, and this
257 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700258 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700259 CollapseWhitespace();
260 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700261 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700262 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700263 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800264}
265
Lee Thomason2c85a712012-01-31 08:24:24 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800268
Lee Thomason56bdd022012-02-09 18:16:58 -0800269// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800270
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800271const char* XMLUtil::ReadBOM( const char* p, bool* bom )
272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700273 *bom = false;
274 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
275 // Check for BOM:
276 if ( *(pu+0) == TIXML_UTF_LEAD_0
277 && *(pu+1) == TIXML_UTF_LEAD_1
278 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
279 *bom = true;
280 p += 3;
281 }
282 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800283}
284
285
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800286void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 const unsigned long BYTE_MASK = 0xBF;
289 const unsigned long BYTE_MARK = 0x80;
290 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 if (input < 0x80) {
293 *length = 1;
294 }
295 else if ( input < 0x800 ) {
296 *length = 2;
297 }
298 else if ( input < 0x10000 ) {
299 *length = 3;
300 }
301 else if ( input < 0x200000 ) {
302 *length = 4;
303 }
304 else {
305 *length = 0; // This code won't covert this correctly anyway.
306 return;
307 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800310
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700311 // Scary scary fall throughs.
312 switch (*length) {
313 case 4:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 3:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 2:
322 --output;
323 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
324 input >>= 6;
325 case 1:
326 --output;
327 *output = (char)(input | FIRST_BYTE_MARK[*length]);
328 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800329}
330
331
332const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 // Presume an entity, and pull it out.
335 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800336
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 if ( *(p+1) == '#' && *(p+2) ) {
338 unsigned long ucs = 0;
339 ptrdiff_t delta = 0;
340 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800341
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 if ( *(p+2) == 'x' ) {
343 // Hexadecimal.
344 if ( !*(p+3) ) {
345 return 0;
346 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800347
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700348 const char* q = p+3;
349 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( !q || !*q ) {
352 return 0;
353 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800354
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 delta = q-p;
356 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 while ( *q != 'x' ) {
359 if ( *q >= '0' && *q <= '9' ) {
360 ucs += mult * (*q - '0');
361 }
362 else if ( *q >= 'a' && *q <= 'f' ) {
363 ucs += mult * (*q - 'a' + 10);
364 }
365 else if ( *q >= 'A' && *q <= 'F' ) {
366 ucs += mult * (*q - 'A' + 10 );
367 }
368 else {
369 return 0;
370 }
371 mult *= 16;
372 --q;
373 }
374 }
375 else {
376 // Decimal.
377 if ( !*(p+2) ) {
378 return 0;
379 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800380
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700381 const char* q = p+2;
382 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800383
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 if ( !q || !*q ) {
385 return 0;
386 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 delta = q-p;
389 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800390
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 while ( *q != '#' ) {
392 if ( *q >= '0' && *q <= '9' ) {
393 ucs += mult * (*q - '0');
394 }
395 else {
396 return 0;
397 }
398 mult *= 10;
399 --q;
400 }
401 }
402 // convert the UCS to UTF-8
403 ConvertUTF32ToUTF8( ucs, value, length );
404 return p + delta + 1;
405 }
406 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800408
409
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700410void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700413}
414
415
416void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700418 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
439
440bool XMLUtil::ToInt( const char* str, int* value )
441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
443 return true;
444 }
445 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
448bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
451 return true;
452 }
453 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700454}
455
456bool XMLUtil::ToBool( const char* str, bool* value )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 int ival = 0;
459 if ( ToInt( str, &ival )) {
460 *value = (ival==0) ? false : true;
461 return true;
462 }
463 if ( StringEqual( str, "true" ) ) {
464 *value = true;
465 return true;
466 }
467 else if ( StringEqual( str, "false" ) ) {
468 *value = false;
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474
475bool XMLUtil::ToFloat( const char* str, float* value )
476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
478 return true;
479 }
480 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700481}
482
483bool XMLUtil::ToDouble( const char* str, double* value )
484{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
486 return true;
487 }
488 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700489}
490
491
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700492char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800493{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 XMLNode* returnNode = 0;
495 char* start = p;
496 p = XMLUtil::SkipWhiteSpace( p );
497 if( !p || !*p ) {
498 return p;
499 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 // What is this thing?
502 // - Elements start with a letter or underscore, but xml is reserved.
503 // - Comments: <!--
504 // - Decleration: <?
505 // - Everthing else is unknown to tinyxml.
506 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800507
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700508 static const char* xmlHeader = { "<?" };
509 static const char* commentHeader = { "<!--" };
510 static const char* dtdHeader = { "<!" };
511 static const char* cdataHeader = { "<![CDATA[" };
512 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800513
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const int xmlHeaderLen = 2;
515 static const int commentHeaderLen = 4;
516 static const int dtdHeaderLen = 2;
517 static const int cdataHeaderLen = 9;
518 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800520#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800521#pragma warning ( push )
522#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
525 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800528#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700530 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
531 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 p += xmlHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700535 returnNode = new (_commentPool.Alloc()) XMLComment( this );
536 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 p += commentHeaderLen;
538 }
539 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700542 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 p += cdataHeaderLen;
544 text->SetCData( true );
545 }
546 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
548 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 p += dtdHeaderLen;
550 }
551 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode = new (_elementPool.Alloc()) XMLElement( this );
553 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 p += elementHeaderLen;
555 }
556 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_textPool.Alloc()) XMLText( this );
558 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p = start; // Back it up, all the text counts.
560 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 *node = returnNode;
563 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800564}
565
566
Lee Thomason751da522012-02-10 08:50:51 -0800567bool XMLDocument::Accept( XMLVisitor* visitor ) const
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( visitor->VisitEnter( *this ) ) {
570 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
571 if ( !node->Accept( visitor ) ) {
572 break;
573 }
574 }
575 }
576 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800577}
Lee Thomason56bdd022012-02-09 18:16:58 -0800578
579
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800580// --------- XMLNode ----------- //
581
582XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700583 _document( doc ),
584 _parent( 0 ),
585 _firstChild( 0 ), _lastChild( 0 ),
586 _prev( 0 ), _next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588}
589
590
591XMLNode::~XMLNode()
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 if ( _parent ) {
595 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800597}
598
599
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800600void XMLNode::SetValue( const char* str, bool staticMem )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700603 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 }
605 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800608}
609
610
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800611void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800612{
Lee Thomason624d43f2012-10-12 10:58:48 -0700613 while( _firstChild ) {
614 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700616
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 DELETE_NODE( node );
618 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700619 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800620}
621
622
623void XMLNode::Unlink( XMLNode* child )
624{
Lee Thomason624d43f2012-10-12 10:58:48 -0700625 TIXMLASSERT( child->_parent == this );
626 if ( child == _firstChild ) {
627 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 if ( child == _lastChild ) {
630 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomasond923c672012-01-23 08:44:25 -0800632
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 if ( child->_prev ) {
634 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 if ( child->_next ) {
637 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800640}
641
642
U-Stream\Leeae25a442012-02-17 17:48:16 -0800643void XMLNode::DeleteChild( XMLNode* node )
644{
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800647}
648
649
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
651{
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( _lastChild ) {
653 TIXMLASSERT( _firstChild );
654 TIXMLASSERT( _lastChild->_next == 0 );
655 _lastChild->_next = addThis;
656 addThis->_prev = _lastChild;
657 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 }
661 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 TIXMLASSERT( _firstChild == 0 );
663 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 addThis->_prev = 0;
666 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670}
671
672
Lee Thomason1ff38e02012-02-14 18:18:16 -0800673XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
674{
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 if ( _firstChild ) {
676 TIXMLASSERT( _lastChild );
677 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800678
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 _firstChild->_prev = addThis;
680 addThis->_next = _firstChild;
681 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 }
685 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 TIXMLASSERT( _lastChild == 0 );
687 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800688
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 addThis->_prev = 0;
690 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800694}
695
696
697XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
698{
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 TIXMLASSERT( afterThis->_parent == this );
700 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 return 0;
702 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800703
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 // The last node or the only node.
706 return InsertEndChild( addThis );
707 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 addThis->_prev = afterThis;
709 addThis->_next = afterThis->_next;
710 afterThis->_next->_prev = addThis;
711 afterThis->_next = addThis;
712 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700713 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714}
715
716
717
718
Lee Thomason56bdd022012-02-09 18:16:58 -0800719const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800720{
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 XMLElement* element = node->ToElement();
723 if ( element ) {
724 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
725 return element;
726 }
727 }
728 }
729 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800730}
731
732
Lee Thomason56bdd022012-02-09 18:16:58 -0800733const XMLElement* XMLNode::LastChildElement( const char* value ) const
734{
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 XMLElement* element = node->ToElement();
737 if ( element ) {
738 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
739 return element;
740 }
741 }
742 }
743 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800744}
745
746
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800747const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
748{
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 if ( element->ToElement()
751 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
752 return element->ToElement();
753 }
754 }
755 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800756}
757
758
759const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
760{
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 if ( element->ToElement()
763 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
764 return element->ToElement();
765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800771char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800772{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 // This is a recursive method, but thinking about it "at the current level"
774 // it is a pretty simple flat list:
775 // <foo/>
776 // <!-- comment -->
777 //
778 // With a special case:
779 // <foo>
780 // </foo>
781 // <!-- comment -->
782 //
783 // Where the closing element (/foo) *must* be the next thing after the opening
784 // element, and the names must match. BUT the tricky bit is that the closing
785 // element will be read by the child.
786 //
787 // 'endTag' is the end tag for this node, it is returned by a call to a child.
788 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800789
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 while( p && *p ) {
791 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800792
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 if ( p == 0 || node == 0 ) {
795 break;
796 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800797
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 StrPair endTag;
799 p = node->ParseDeep( p, &endTag );
800 if ( !p ) {
801 DELETE_NODE( node );
802 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 if ( !_document->Error() ) {
804 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
806 break;
807 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800808
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 // We read the end tag. Return it to the parent.
810 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
811 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
814 DELETE_NODE( node );
815 return p;
816 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800817
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 // Handle an end tag returned to this level.
819 // And handle a bunch of annoying errors.
820 XMLElement* ele = node->ToElement();
821 if ( ele ) {
822 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 p = 0;
825 }
826 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 p = 0;
829 }
830 else if ( !endTag.Empty() ) {
831 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 p = 0;
834 }
835 }
836 }
837 if ( p == 0 ) {
838 DELETE_NODE( node );
839 node = 0;
840 }
841 if ( node ) {
842 this->InsertEndChild( node );
843 }
844 }
845 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800846}
847
Lee Thomason5492a1c2012-01-23 15:32:10 -0800848// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800849char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800850{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 const char* start = p;
852 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 }
857 return p;
858 }
859 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
861 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 flags |= StrPair::COLLAPSE_WHITESPACE;
863 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700864
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 }
869 if ( p && *p ) {
870 return p-1;
871 }
872 }
873 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874}
875
876
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800877XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
882 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
883 text->SetCData( this->CData() );
884 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800885}
886
887
888bool XMLText::ShallowEqual( const XMLNode* compare ) const
889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800891}
892
893
Lee Thomason56bdd022012-02-09 18:16:58 -0800894bool XMLText::Accept( XMLVisitor* visitor ) const
895{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800897}
898
899
Lee Thomason3f57d272012-01-11 15:30:03 -0800900// --------- XMLComment ---------- //
901
Lee Thomasone4422302012-01-20 17:59:50 -0800902XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800903{
904}
905
906
Lee Thomasonce0763e2012-01-11 15:43:54 -0800907XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800908{
Lee Thomason3f57d272012-01-11 15:30:03 -0800909}
910
911
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800912char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 // Comment parses as text.
915 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700918 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 }
920 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800921}
922
923
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
925{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700927 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
930 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800931}
932
933
934bool XMLComment::ShallowEqual( const XMLNode* compare ) const
935{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800937}
938
939
Lee Thomason751da522012-02-10 08:50:51 -0800940bool XMLComment::Accept( XMLVisitor* visitor ) const
941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800943}
Lee Thomason56bdd022012-02-09 18:16:58 -0800944
945
Lee Thomason50f97b22012-02-11 16:33:40 -0800946// --------- XMLDeclaration ---------- //
947
948XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
949{
950}
951
952
953XMLDeclaration::~XMLDeclaration()
954{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800956}
957
958
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800959char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800960{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 // Declaration parses as text.
962 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700963 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700965 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 }
967 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800968}
969
970
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800971XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
972{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700974 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 }
976 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
977 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800978}
979
980
981bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984}
985
986
987
Lee Thomason50f97b22012-02-11 16:33:40 -0800988bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800991}
992
993// --------- XMLUnknown ---------- //
994
995XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
996{
997}
998
999
1000XMLUnknown::~XMLUnknown()
1001{
1002}
1003
1004
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001005char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001006{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 // Unknown parses as text.
1008 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001009
Lee Thomason624d43f2012-10-12 10:58:48 -07001010 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001012 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 }
1014 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001015}
1016
1017
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001018XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 }
1023 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1024 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001025}
1026
1027
1028bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1029{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001031}
1032
1033
Lee Thomason50f97b22012-02-11 16:33:40 -08001034bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001037}
1038
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001039// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001040char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001041{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001043 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 if ( !p || !*p ) {
1045 return 0;
1046 }
Lee Thomason22aead12012-01-23 13:29:35 -08001047
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 // Skip white space before =
1049 p = XMLUtil::SkipWhiteSpace( p );
1050 if ( !p || *p != '=' ) {
1051 return 0;
1052 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001053
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 ++p; // move up to opening quote
1055 p = XMLUtil::SkipWhiteSpace( p );
1056 if ( *p != '\"' && *p != '\'' ) {
1057 return 0;
1058 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001059
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 char endTag[2] = { *p, 0 };
1061 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001062
Lee Thomason624d43f2012-10-12 10:58:48 -07001063 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001065}
1066
1067
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001068void XMLAttribute::SetName( const char* n )
1069{
Lee Thomason624d43f2012-10-12 10:58:48 -07001070 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001071}
1072
1073
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001074int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 if ( XMLUtil::ToInt( Value(), value )) {
1077 return XML_NO_ERROR;
1078 }
1079 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001080}
1081
1082
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001083int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( XMLUtil::ToUnsigned( Value(), value )) {
1086 return XML_NO_ERROR;
1087 }
1088 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001089}
1090
1091
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( XMLUtil::ToBool( Value(), value )) {
1095 return XML_NO_ERROR;
1096 }
1097 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001098}
1099
1100
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001101int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 if ( XMLUtil::ToFloat( Value(), value )) {
1104 return XML_NO_ERROR;
1105 }
1106 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001107}
1108
1109
1110int XMLAttribute::QueryDoubleValue( double* value ) const
1111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( XMLUtil::ToDouble( Value(), value )) {
1113 return XML_NO_ERROR;
1114 }
1115 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001116}
1117
1118
1119void XMLAttribute::SetAttribute( const char* v )
1120{
Lee Thomason624d43f2012-10-12 10:58:48 -07001121 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122}
1123
1124
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125void XMLAttribute::SetAttribute( int v )
1126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 char buf[BUF_SIZE];
1128 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001131
1132
1133void XMLAttribute::SetAttribute( unsigned v )
1134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 char buf[BUF_SIZE];
1136 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001137 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001138}
1139
1140
1141void XMLAttribute::SetAttribute( bool v )
1142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 char buf[BUF_SIZE];
1144 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001145 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001146}
1147
1148void XMLAttribute::SetAttribute( double v )
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 char buf[BUF_SIZE];
1151 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001153}
1154
1155void XMLAttribute::SetAttribute( float v )
1156{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 char buf[BUF_SIZE];
1158 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001160}
1161
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001162
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001163// --------- XMLElement ---------- //
1164XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 _closingType( 0 ),
1166 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001167{
1168}
1169
1170
1171XMLElement::~XMLElement()
1172{
Lee Thomason624d43f2012-10-12 10:58:48 -07001173 while( _rootAttribute ) {
1174 XMLAttribute* next = _rootAttribute->_next;
1175 DELETE_ATTRIBUTE( _rootAttribute );
1176 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001178}
1179
1180
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001181XMLAttribute* XMLElement::FindAttribute( const char* name )
1182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001184 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1186 return a;
1187 }
1188 }
1189 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001190}
1191
1192
1193const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1198 return a;
1199 }
1200 }
1201 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001202}
1203
1204
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001205const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 const XMLAttribute* a = FindAttribute( name );
1208 if ( !a ) {
1209 return 0;
1210 }
1211 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1212 return a->Value();
1213 }
1214 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001215}
1216
1217
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001218const char* XMLElement::GetText() const
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 if ( FirstChild() && FirstChild()->ToText() ) {
1221 return FirstChild()->ToText()->Value();
1222 }
1223 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001224}
1225
1226
Lee Thomason21be8822012-07-15 17:27:22 -07001227int XMLElement::QueryIntText( int* _value ) const
1228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( FirstChild() && FirstChild()->ToText() ) {
1230 const char* t = FirstChild()->ToText()->Value();
1231 if ( XMLUtil::ToInt( t, _value ) ) {
1232 return XML_SUCCESS;
1233 }
1234 return XML_CAN_NOT_CONVERT_TEXT;
1235 }
1236 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001237}
1238
1239
1240int XMLElement::QueryUnsignedText( unsigned* _value ) const
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 if ( FirstChild() && FirstChild()->ToText() ) {
1243 const char* t = FirstChild()->ToText()->Value();
1244 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1245 return XML_SUCCESS;
1246 }
1247 return XML_CAN_NOT_CONVERT_TEXT;
1248 }
1249 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001250}
1251
1252
1253int XMLElement::QueryBoolText( bool* _value ) const
1254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( FirstChild() && FirstChild()->ToText() ) {
1256 const char* t = FirstChild()->ToText()->Value();
1257 if ( XMLUtil::ToBool( t, _value ) ) {
1258 return XML_SUCCESS;
1259 }
1260 return XML_CAN_NOT_CONVERT_TEXT;
1261 }
1262 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001263}
1264
1265
1266int XMLElement::QueryDoubleText( double* _value ) const
1267{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 if ( FirstChild() && FirstChild()->ToText() ) {
1269 const char* t = FirstChild()->ToText()->Value();
1270 if ( XMLUtil::ToDouble( t, _value ) ) {
1271 return XML_SUCCESS;
1272 }
1273 return XML_CAN_NOT_CONVERT_TEXT;
1274 }
1275 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001276}
1277
1278
1279int XMLElement::QueryFloatText( float* _value ) const
1280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 if ( FirstChild() && FirstChild()->ToText() ) {
1282 const char* t = FirstChild()->ToText()->Value();
1283 if ( XMLUtil::ToFloat( t, _value ) ) {
1284 return XML_SUCCESS;
1285 }
1286 return XML_CAN_NOT_CONVERT_TEXT;
1287 }
1288 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001289}
1290
1291
1292
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001293XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 XMLAttribute* last = 0;
1296 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001299 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1301 break;
1302 }
1303 }
1304 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001305 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1306 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001308 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 }
1310 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 }
1313 attrib->SetName( name );
1314 }
1315 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001316}
1317
1318
U-Stream\Leeae25a442012-02-17 17:48:16 -08001319void XMLElement::DeleteAttribute( const char* name )
1320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001322 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1324 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 }
1327 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 }
1330 DELETE_ATTRIBUTE( a );
1331 break;
1332 }
1333 prev = a;
1334 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001335}
1336
1337
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001338char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 const char* start = p;
1341 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001342
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 // Read the attributes.
1344 while( p ) {
1345 p = XMLUtil::SkipWhiteSpace( p );
1346 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001347 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 return 0;
1349 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001350
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 // attribute.
1352 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001353 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1354 attrib->_memPool = &_document->_attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001355
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 if ( !p || Attribute( attrib->Name() ) ) {
1358 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 return 0;
1361 }
1362 // There is a minor bug here: if the attribute in the source xml
1363 // document is duplicated, it will not be detected and the
1364 // attribute will be doubly added. However, tracking the 'prevAttribute'
1365 // avoids re-scanning the attribute list. Preferring performance for
1366 // now, may reconsider in the future.
1367 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001368 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 }
1370 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 }
1373 prevAttribute = attrib;
1374 }
1375 // end of the tag
1376 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 return p+2; // done; sealed element.
1379 }
1380 // end of the tag
1381 else if ( *p == '>' ) {
1382 ++p;
1383 break;
1384 }
1385 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return 0;
1388 }
1389 }
1390 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001391}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001392
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001393
Lee Thomason67d61312012-01-24 16:01:51 -08001394//
1395// <ele></ele>
1396// <ele>foo<b>bar</b></ele>
1397//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001398char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001399{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 // Read the element name.
1401 p = XMLUtil::SkipWhiteSpace( p );
1402 if ( !p ) {
1403 return 0;
1404 }
Lee Thomason67d61312012-01-24 16:01:51 -08001405
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 // The closing element is the </element> form. It is
1407 // parsed just like a regular element then deleted from
1408 // the DOM.
1409 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 ++p;
1412 }
Lee Thomason67d61312012-01-24 16:01:51 -08001413
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 p = _value.ParseName( p );
1415 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 return 0;
1417 }
Lee Thomason67d61312012-01-24 16:01:51 -08001418
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 return p;
1422 }
Lee Thomason67d61312012-01-24 16:01:51 -08001423
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 p = XMLNode::ParseDeep( p, strPair );
1425 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001426}
1427
1428
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001429
1430XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 }
1435 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1436 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1437 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1438 }
1439 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001440}
1441
1442
1443bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 const XMLElement* other = compare->ToElement();
1446 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001447
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 const XMLAttribute* a=FirstAttribute();
1449 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001450
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 while ( a && b ) {
1452 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1453 return false;
1454 }
1455 a = a->Next();
1456 b = b->Next();
1457 }
1458 if ( a || b ) {
1459 // different count
1460 return false;
1461 }
1462 return true;
1463 }
1464 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001465}
1466
1467
Lee Thomason751da522012-02-10 08:50:51 -08001468bool XMLElement::Accept( XMLVisitor* visitor ) const
1469{
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1472 if ( !node->Accept( visitor ) ) {
1473 break;
1474 }
1475 }
1476 }
1477 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001478}
Lee Thomason56bdd022012-02-09 18:16:58 -08001479
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001480
Lee Thomason3f57d272012-01-11 15:30:03 -08001481// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001482XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 _writeBOM( false ),
1485 _processEntities( processEntities ),
1486 _errorID( 0 ),
1487 _whitespace( whitespace ),
1488 _errorStr1( 0 ),
1489 _errorStr2( 0 ),
1490 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001491{
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001493}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001494
1495
Lee Thomason3f57d272012-01-11 15:30:03 -08001496XMLDocument::~XMLDocument()
1497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001500
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001501#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 textPool.Trace( "text" );
1503 elementPool.Trace( "element" );
1504 commentPool.Trace( "comment" );
1505 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001506#endif
1507
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 TIXMLASSERT( _textPool.CurrentAllocs() == 0 );
1509 TIXMLASSERT( _elementPool.CurrentAllocs() == 0 );
1510 TIXMLASSERT( _commentPool.CurrentAllocs() == 0 );
1511 TIXMLASSERT( _attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001512}
1513
1514
Lee Thomason18d68bd2012-01-26 18:17:26 -08001515void XMLDocument::InitDocument()
1516{
Lee Thomason624d43f2012-10-12 10:58:48 -07001517 _errorID = XML_NO_ERROR;
1518 _errorStr1 = 0;
1519 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001520
Lee Thomason624d43f2012-10-12 10:58:48 -07001521 delete [] _charBuffer;
1522 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001523}
1524
Lee Thomason3f57d272012-01-11 15:30:03 -08001525
Lee Thomason2c85a712012-01-31 08:24:24 -08001526XMLElement* XMLDocument::NewElement( const char* name )
1527{
Lee Thomason624d43f2012-10-12 10:58:48 -07001528 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1529 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 ele->SetName( name );
1531 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001532}
1533
1534
Lee Thomason1ff38e02012-02-14 18:18:16 -08001535XMLComment* XMLDocument::NewComment( const char* str )
1536{
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1538 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 comment->SetValue( str );
1540 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001541}
1542
1543
1544XMLText* XMLDocument::NewText( const char* str )
1545{
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1547 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 text->SetValue( str );
1549 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001550}
1551
1552
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001553XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1554{
Lee Thomason624d43f2012-10-12 10:58:48 -07001555 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1556 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1558 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001559}
1560
1561
1562XMLUnknown* XMLDocument::NewUnknown( const char* str )
1563{
Lee Thomason624d43f2012-10-12 10:58:48 -07001564 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1565 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 unk->SetValue( str );
1567 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001568}
1569
1570
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001571int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 DeleteChildren();
1574 InitDocument();
1575 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1578 errno_t err = fopen_s(&fp, filename, "rb" );
1579 if ( !fp || err) {
1580#else
1581 fp = fopen( filename, "rb" );
1582 if ( !fp) {
1583#endif
1584 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001585 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 }
1587 LoadFile( fp );
1588 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001589 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001590}
1591
1592
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001593int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 DeleteChildren();
1596 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001597
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 fseek( fp, 0, SEEK_END );
1599 size_t size = ftell( fp );
1600 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001601
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( size == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001605
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 _charBuffer = new char[size+1];
1607 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 if ( read != size ) {
1609 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001612
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001614
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 if ( !p || !*p ) {
1619 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001622
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1624 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001625}
1626
1627
Robert Reif312a20f2012-09-08 19:33:57 -04001628int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 FILE* fp = 0;
1631#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1632 errno_t err = fopen_s(&fp, filename, "w" );
1633 if ( !fp || err) {
1634#else
1635 fp = fopen( filename, "w" );
1636 if ( !fp) {
1637#endif
1638 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001639 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 }
1641 SaveFile(fp, compact);
1642 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001644}
1645
1646
Robert Reif312a20f2012-09-08 19:33:57 -04001647int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001648{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 XMLPrinter stream( fp, compact );
1650 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001652}
1653
Lee Thomason1ff38e02012-02-14 18:18:16 -08001654
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001655int XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 DeleteChildren();
1658 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001659
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 if ( !p || !*p ) {
1661 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 }
1664 if ( len == (size_t)(-1) ) {
1665 len = strlen( p );
1666 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 _charBuffer = new char[ len+1 ];
1668 memcpy( _charBuffer, p, len );
1669 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001670
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 if ( !p || !*p ) {
1674 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001677
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 ParseDeep( _charBuffer, 0 );
1679 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001680}
1681
1682
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001683void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001684{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 XMLPrinter stdStreamer( stdout );
1686 if ( !streamer ) {
1687 streamer = &stdStreamer;
1688 }
1689 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001690}
1691
1692
Lee Thomason67d61312012-01-24 16:01:51 -08001693void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1694{
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 _errorID = error;
1696 _errorStr1 = str1;
1697 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001698}
1699
Lee Thomason5cae8972012-01-24 18:03:07 -08001700
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001701void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001702{
Lee Thomason624d43f2012-10-12 10:58:48 -07001703 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 static const int LEN = 20;
1705 char buf1[LEN] = { 0 };
1706 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001707
Lee Thomason624d43f2012-10-12 10:58:48 -07001708 if ( _errorStr1 ) {
1709 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 if ( _errorStr2 ) {
1712 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001714
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001715 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001716 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001718}
1719
1720
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001721XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 _elementJustOpened( false ),
1723 _firstElement( true ),
1724 _fp( file ),
1725 _depth( 0 ),
1726 _textDepth( -1 ),
1727 _processEntities( true ),
1728 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001729{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 _entityFlag[i] = false;
1732 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 }
1734 for( int i=0; i<NUM_ENTITIES; ++i ) {
1735 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1736 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 }
1739 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 _restrictedEntityFlag[(int)'&'] = true;
1741 _restrictedEntityFlag[(int)'<'] = true;
1742 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1743 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001744}
1745
1746
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001747void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001748{
1749 va_list va;
1750 va_start( va, format );
1751
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 if ( _fp ) {
1753 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 else {
1756 // This seems brutally complex. Haven't figured out a better
1757 // way on windows.
1758#ifdef _MSC_VER
1759 int len = -1;
1760 int expand = 1000;
1761 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 if ( len < 0 ) {
1764 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001765 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 }
1767 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 char* p = _buffer.PushArr( len ) - 1;
1769 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770#else
1771 int len = vsnprintf( 0, 0, format, va );
1772 // Close out and re-start the va-args
1773 va_end( va );
1774 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 vsnprintf( p, len+1, format, va );
1777#endif
1778 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001779 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001780}
1781
1782
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001783void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001784{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 for( int i=0; i<depth; ++i ) {
1786 Print( " " );
1787 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001788}
1789
1790
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001791void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001792{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 // Look for runs of bytes between entities to print.
1794 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001796
Lee Thomason624d43f2012-10-12 10:58:48 -07001797 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 while ( *q ) {
1799 // Remember, char is sometimes signed. (How many times has that bitten me?)
1800 if ( *q > 0 && *q < ENTITY_RANGE ) {
1801 // Check for entities. If one is found, flush
1802 // the stream up until the entity, write the
1803 // entity, and keep looking.
1804 if ( flag[(unsigned)(*q)] ) {
1805 while ( p < q ) {
1806 Print( "%c", *p );
1807 ++p;
1808 }
1809 for( int i=0; i<NUM_ENTITIES; ++i ) {
1810 if ( entities[i].value == *q ) {
1811 Print( "&%s;", entities[i].pattern );
1812 break;
1813 }
1814 }
1815 ++p;
1816 }
1817 }
1818 ++q;
1819 }
1820 }
1821 // Flush the remaining string. This will be the entire
1822 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 Print( "%s", p );
1825 }
Lee Thomason857b8682012-01-25 17:50:25 -08001826}
1827
U-Stream\Leeae25a442012-02-17 17:48:16 -08001828
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001829void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001830{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1832 if ( writeBOM ) {
1833 Print( "%s", bom );
1834 }
1835 if ( writeDec ) {
1836 PushDeclaration( "xml version=\"1.0\"" );
1837 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001838}
1839
1840
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001841void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001842{
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 SealElement();
1845 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001847
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001852
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _elementJustOpened = true;
1855 _firstElement = false;
1856 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001857}
1858
1859
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001860void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001861{
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 Print( " %s=\"", name );
1864 PrintString( value, false );
1865 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001866}
1867
1868
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001869void XMLPrinter::PushAttribute( const char* name, int v )
1870{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 char buf[BUF_SIZE];
1872 XMLUtil::ToStr( v, buf, BUF_SIZE );
1873 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001874}
1875
1876
1877void XMLPrinter::PushAttribute( const char* name, unsigned v )
1878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 char buf[BUF_SIZE];
1880 XMLUtil::ToStr( v, buf, BUF_SIZE );
1881 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001882}
1883
1884
1885void XMLPrinter::PushAttribute( const char* name, bool v )
1886{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 char buf[BUF_SIZE];
1888 XMLUtil::ToStr( v, buf, BUF_SIZE );
1889 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001890}
1891
1892
1893void XMLPrinter::PushAttribute( const char* name, double v )
1894{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 char buf[BUF_SIZE];
1896 XMLUtil::ToStr( v, buf, BUF_SIZE );
1897 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001898}
1899
1900
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001901void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001902{
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 --_depth;
1904 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001905
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 Print( "/>" );
1908 }
1909 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 }
1914 Print( "</%s>", name );
1915 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001916
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 if ( _textDepth == _depth ) {
1918 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 Print( "\n" );
1922 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001924}
1925
1926
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001927void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001928{
Lee Thomason624d43f2012-10-12 10:58:48 -07001929 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001931}
1932
1933
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001934void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001935{
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001937
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 SealElement();
1940 }
1941 if ( cdata ) {
1942 Print( "<![CDATA[" );
1943 Print( "%s", text );
1944 Print( "]]>" );
1945 }
1946 else {
1947 PrintString( text, true );
1948 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001949}
1950
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001951void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 char buf[BUF_SIZE];
1954 XMLUtil::ToStr( value, buf, BUF_SIZE );
1955 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001956}
1957
1958
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001959void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001960{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 char buf[BUF_SIZE];
1962 XMLUtil::ToStr( value, buf, BUF_SIZE );
1963 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001964}
1965
1966
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001967void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001968{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 char buf[BUF_SIZE];
1970 XMLUtil::ToStr( value, buf, BUF_SIZE );
1971 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001972}
1973
1974
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001975void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 char buf[BUF_SIZE];
1978 XMLUtil::ToStr( value, buf, BUF_SIZE );
1979 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001980}
1981
1982
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001983void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 char buf[BUF_SIZE];
1986 XMLUtil::ToStr( value, buf, BUF_SIZE );
1987 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001988}
1989
Lee Thomason5cae8972012-01-24 18:03:07 -08001990
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001991void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001992{
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 SealElement();
1995 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001996 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001998 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002002}
Lee Thomason751da522012-02-10 08:50:51 -08002003
2004
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002005void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002006{
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 SealElement();
2009 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002012 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002014 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002016}
2017
2018
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002019void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002020{
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 SealElement();
2023 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002030}
2031
2032
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002033bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002034{
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 if ( doc.HasBOM() ) {
2037 PushHeader( true, false );
2038 }
2039 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 OpenElement( element.Name() );
2046 while ( attribute ) {
2047 PushAttribute( attribute->Name(), attribute->Value() );
2048 attribute = attribute->Next();
2049 }
2050 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002051}
2052
2053
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002054bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 CloseElement();
2057 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002058}
2059
2060
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002061bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 PushText( text.Value(), text.CData() );
2064 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002065}
2066
2067
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002068bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 PushComment( comment.Value() );
2071 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002072}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 PushDeclaration( declaration.Value() );
2077 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002078}
2079
2080
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002081bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 PushUnknown( unknown.Value() );
2084 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002085}