blob: 143d30ab55cec72d869993e7dbea0feb9bd3b84b [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.
27#ifdef ANDROID_NDK
28 #include <stddef.h>
29#else
30 #include <cstddef>
31#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 ) { \
52 if ( node ) { \
53 MemPool* pool = node->memPool; \
54 node->~XMLNode(); \
55 pool->Free( node ); \
56 } \
57}
58#define DELETE_ATTRIBUTE( attrib ) { \
59 if ( attrib ) { \
60 MemPool* pool = attrib->memPool; \
61 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 {
67 const char* pattern;
68 int length;
69 char value;
70};
71
72static const int NUM_ENTITIES = 5;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070073static const Entity entities[NUM_ENTITIES] =
Lee Thomason8ee79892012-01-25 17:44:30 -080074{
Lee Thomason18d68bd2012-01-26 18:17:26 -080075 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080076 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080077 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080078 { "lt", 2, '<' },
79 { "gt", 2, '>' }
80};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
85 Reset();
86}
87
88
89void StrPair::Reset()
90{
91 if ( flags & NEEDS_DELETE ) {
92 delete [] start;
93 }
94 flags = 0;
95 start = 0;
96 end = 0;
97}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
102 Reset();
103 size_t len = strlen( str );
104 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800105 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800106 end = start + len;
107 this->flags = flags | NEEDS_DELETE;
108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
113 TIXMLASSERT( endTag && *endTag );
114
115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
119 // 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;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700126 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
133 char* start = p;
134
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135 if ( !start || !(*start) ) {
136 return 0;
137 }
138
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800139 while( *p && (
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700140 XMLUtil::IsAlphaNum( (unsigned char) *p )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141 || *p == '_'
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -0700142 || *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.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800145 {
146 ++p;
147 }
148
149 if ( p > start ) {
150 Set( start, p, 0 );
151 return p;
152 }
153 return 0;
154}
155
156
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700157void StrPair::CollapseWhitespace()
158{
159 // Trim leading space.
160 start = XMLUtil::SkipWhiteSpace( start );
161
162 if ( start && *start ) {
163 char* p = start; // the read pointer
164 char* q = start; // the write pointer
165
166 while( *p ) {
167 if ( XMLUtil::IsWhiteSpace( *p )) {
168 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700169 if ( *p == 0 )
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700170 break; // don't write to q; this trims the trailing space.
171 *q = ' ';
172 ++q;
173 }
174 *q = *p;
175 ++q;
176 ++p;
177 }
178 *q = 0;
179 }
180}
181
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800182
Lee Thomasone4422302012-01-20 17:59:50 -0800183const char* StrPair::GetStr()
184{
185 if ( flags & NEEDS_FLUSH ) {
186 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800187 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800188
Lee Thomason8ee79892012-01-25 17:44:30 -0800189 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800190 char* p = start; // the read pointer
191 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800192
193 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800194 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800195 // 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 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800204 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800205 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800206 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800207 if ( *(p+1) == CR ) {
208 p += 2;
209 }
210 else {
211 ++p;
212 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800213 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800214 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800215 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800216 // Entities handled by tinyXML2:
217 // - special entities in the entity table [in/out]
218 // - numeric character reference [in]
219 // &#20013; or &#x4e2d;
220
221 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];
Lee Thomason8ee79892012-01-25 17:44:30 -0800227 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800228 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800229 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800230 else {
PKEuSc28ba3a2012-07-16 03:08:47 -0700231 int i=0;
232 for(; i<NUM_ENTITIES; ++i ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800233 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700234 && *(p+entities[i].length+1) == ';' )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800235 {
236 // Found an entity convert;
237 *q = entities[i].value;
238 ++q;
239 p += entities[i].length + 2;
240 break;
241 }
242 }
243 if ( i == NUM_ENTITIES ) {
244 // fixme: treat as error?
245 ++p;
246 ++q;
247 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800248 }
249 }
Lee Thomasone4422302012-01-20 17:59:50 -0800250 else {
251 *q = *p;
252 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800253 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800254 }
255 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800256 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800257 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700258 // The loop below has plenty going on, and this
259 // is a less useful mode. Break it out.
260 if ( flags & COLLAPSE_WHITESPACE ) {
261 CollapseWhitespace();
262 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800263 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800264 }
265 return start;
266}
267
Lee Thomason2c85a712012-01-31 08:24:24 -0800268
Lee Thomasone4422302012-01-20 17:59:50 -0800269
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800270
Lee Thomason56bdd022012-02-09 18:16:58 -0800271// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800272
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800273const char* XMLUtil::ReadBOM( const char* p, bool* bom )
274{
275 *bom = false;
276 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
277 // Check for BOM:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700278 if ( *(pu+0) == TIXML_UTF_LEAD_0
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279 && *(pu+1) == TIXML_UTF_LEAD_1
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700280 && *(pu+2) == TIXML_UTF_LEAD_2 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281 {
282 *bom = true;
283 p += 3;
284 }
285 return p;
286}
287
288
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800289void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
290{
291 const unsigned long BYTE_MASK = 0xBF;
292 const unsigned long BYTE_MARK = 0x80;
293 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
294
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700295 if (input < 0x80)
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800296 *length = 1;
297 else if ( input < 0x800 )
298 *length = 2;
299 else if ( input < 0x10000 )
300 *length = 3;
301 else if ( input < 0x200000 )
302 *length = 4;
303 else
304 { *length = 0; return; } // This code won't covert this correctly anyway.
305
306 output += *length;
307
308 // Scary scary fall throughs.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700309 switch (*length)
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800310 {
311 case 4:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700312 --output;
313 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800314 input >>= 6;
315 case 3:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700316 --output;
317 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800318 input >>= 6;
319 case 2:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700320 --output;
321 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800322 input >>= 6;
323 case 1:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700324 --output;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800325 *output = (char)(input | FIRST_BYTE_MARK[*length]);
326 }
327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
332 // Presume an entity, and pull it out.
333 *length = 0;
334
335 if ( *(p+1) == '#' && *(p+2) )
336 {
337 unsigned long ucs = 0;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200338 ptrdiff_t delta = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339 unsigned mult = 1;
340
341 if ( *(p+2) == 'x' )
342 {
343 // Hexadecimal.
344 if ( !*(p+3) ) return 0;
345
346 const char* q = p+3;
347 q = strchr( q, ';' );
348
349 if ( !q || !*q ) return 0;
350
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200351 delta = q-p;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352 --q;
353
354 while ( *q != 'x' )
355 {
356 if ( *q >= '0' && *q <= '9' )
357 ucs += mult * (*q - '0');
358 else if ( *q >= 'a' && *q <= 'f' )
359 ucs += mult * (*q - 'a' + 10);
360 else if ( *q >= 'A' && *q <= 'F' )
361 ucs += mult * (*q - 'A' + 10 );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700362 else
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363 return 0;
364 mult *= 16;
365 --q;
366 }
367 }
368 else
369 {
370 // Decimal.
371 if ( !*(p+2) ) return 0;
372
373 const char* q = p+2;
374 q = strchr( q, ';' );
375
376 if ( !q || !*q ) return 0;
377
378 delta = q-p;
379 --q;
380
381 while ( *q != '#' )
382 {
383 if ( *q >= '0' && *q <= '9' )
384 ucs += mult * (*q - '0');
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700385 else
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386 return 0;
387 mult *= 10;
388 --q;
389 }
390 }
391 // convert the UCS to UTF-8
392 ConvertUTF32ToUTF8( ucs, value, length );
393 return p + delta + 1;
394 }
395 return p+1;
396}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800397
398
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700399void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700400{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700401 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700402}
403
404
405void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
406{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700407 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700408}
409
410
411void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
412{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700413 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700414}
415
416
417void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
418{
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -0700419 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700420}
421
422
423void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
424{
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -0700425 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700426}
427
428
429bool XMLUtil::ToInt( const char* str, int* value )
430{
431 if ( TIXML_SSCANF( str, "%d", value ) == 1 )
432 return true;
433 return false;
434}
435
436bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
437{
438 if ( TIXML_SSCANF( str, "%u", value ) == 1 )
439 return true;
440 return false;
441}
442
443bool XMLUtil::ToBool( const char* str, bool* value )
444{
445 int ival = 0;
446 if ( ToInt( str, &ival )) {
447 *value = (ival==0) ? false : true;
448 return true;
449 }
450 if ( StringEqual( str, "true" ) ) {
451 *value = true;
452 return true;
453 }
454 else if ( StringEqual( str, "false" ) ) {
455 *value = false;
456 return true;
457 }
458 return false;
459}
460
461
462bool XMLUtil::ToFloat( const char* str, float* value )
463{
464 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
465 return true;
466 }
467 return false;
468}
469
470bool XMLUtil::ToDouble( const char* str, double* value )
471{
472 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
473 return true;
474 }
475 return false;
476}
477
478
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700479char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800480{
481 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800482 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800483 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800484 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800485 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800486 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800487 }
488
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700489 // What is this thing?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800490 // - Elements start with a letter or underscore, but xml is reserved.
491 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800492 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800493 // - Everthing else is unknown to tinyxml.
494 //
495
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800496 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800497 static const char* commentHeader = { "<!--" };
498 static const char* dtdHeader = { "<!" };
499 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800500 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800502 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800503 static const int commentHeaderLen = 4;
504 static const int dtdHeaderLen = 2;
505 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800506 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800507
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800508#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800509#pragma warning ( push )
510#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800511#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800512 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
513 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800514#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800515#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800516#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800517 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
518 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
519 returnNode->memPool = &commentPool;
520 p += xmlHeaderLen;
521 }
522 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800523 returnNode = new (commentPool.Alloc()) XMLComment( this );
524 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525 p += commentHeaderLen;
526 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800527 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
528 XMLText* text = new (textPool.Alloc()) XMLText( this );
529 returnNode = text;
530 returnNode->memPool = &textPool;
531 p += cdataHeaderLen;
532 text->SetCData( true );
533 }
534 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
535 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
536 returnNode->memPool = &commentPool;
537 p += dtdHeaderLen;
538 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800539 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800540 returnNode = new (elementPool.Alloc()) XMLElement( this );
541 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800542 p += elementHeaderLen;
543 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800544 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800545 returnNode = new (textPool.Alloc()) XMLText( this );
546 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800547 p = start; // Back it up, all the text counts.
548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800549
550 *node = returnNode;
551 return p;
552}
553
554
Lee Thomason751da522012-02-10 08:50:51 -0800555bool XMLDocument::Accept( XMLVisitor* visitor ) const
556{
557 if ( visitor->VisitEnter( *this ) )
558 {
559 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
560 {
561 if ( !node->Accept( visitor ) )
562 break;
563 }
564 }
565 return visitor->VisitExit( *this );
566}
Lee Thomason56bdd022012-02-09 18:16:58 -0800567
568
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800569// --------- XMLNode ----------- //
570
571XMLNode::XMLNode( XMLDocument* doc ) :
572 document( doc ),
573 parent( 0 ),
574 firstChild( 0 ), lastChild( 0 ),
575 prev( 0 ), next( 0 )
576{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577}
578
579
580XMLNode::~XMLNode()
581{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800582 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800583 if ( parent ) {
584 parent->Unlink( this );
585 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800586}
587
588
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800589void XMLNode::SetValue( const char* str, bool staticMem )
590{
591 if ( staticMem )
592 value.SetInternedStr( str );
593 else
594 value.SetStr( str );
595}
596
597
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800598void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800599{
Lee Thomasond923c672012-01-23 08:44:25 -0800600 while( firstChild ) {
601 XMLNode* node = firstChild;
602 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700603
Lee Thomason43f59302012-02-06 18:18:11 -0800604 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800606 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800607}
608
609
610void XMLNode::Unlink( XMLNode* child )
611{
612 TIXMLASSERT( child->parent == this );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700613 if ( child == firstChild )
Lee Thomasond923c672012-01-23 08:44:25 -0800614 firstChild = firstChild->next;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700615 if ( child == lastChild )
Lee Thomasond923c672012-01-23 08:44:25 -0800616 lastChild = lastChild->prev;
617
618 if ( child->prev ) {
619 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800620 }
Lee Thomasond923c672012-01-23 08:44:25 -0800621 if ( child->next ) {
622 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800623 }
Lee Thomasond923c672012-01-23 08:44:25 -0800624 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800625}
626
627
U-Stream\Leeae25a442012-02-17 17:48:16 -0800628void XMLNode::DeleteChild( XMLNode* node )
629{
630 TIXMLASSERT( node->parent == this );
631 DELETE_NODE( node );
632}
633
634
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
636{
637 if ( lastChild ) {
638 TIXMLASSERT( firstChild );
639 TIXMLASSERT( lastChild->next == 0 );
640 lastChild->next = addThis;
641 addThis->prev = lastChild;
642 lastChild = addThis;
643
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800644 addThis->next = 0;
645 }
646 else {
647 TIXMLASSERT( firstChild == 0 );
648 firstChild = lastChild = addThis;
649
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650 addThis->prev = 0;
651 addThis->next = 0;
652 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800653 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654 return addThis;
655}
656
657
Lee Thomason1ff38e02012-02-14 18:18:16 -0800658XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
659{
660 if ( firstChild ) {
661 TIXMLASSERT( lastChild );
662 TIXMLASSERT( firstChild->prev == 0 );
663
664 firstChild->prev = addThis;
665 addThis->next = firstChild;
666 firstChild = addThis;
667
Lee Thomason1ff38e02012-02-14 18:18:16 -0800668 addThis->prev = 0;
669 }
670 else {
671 TIXMLASSERT( lastChild == 0 );
672 firstChild = lastChild = addThis;
673
Lee Thomason1ff38e02012-02-14 18:18:16 -0800674 addThis->prev = 0;
675 addThis->next = 0;
676 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800677 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800678 return addThis;
679}
680
681
682XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
683{
684 TIXMLASSERT( afterThis->parent == this );
685 if ( afterThis->parent != this )
686 return 0;
687
688 if ( afterThis->next == 0 ) {
689 // The last node or the only node.
690 return InsertEndChild( addThis );
691 }
692 addThis->prev = afterThis;
693 addThis->next = afterThis->next;
694 afterThis->next->prev = addThis;
695 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800696 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697 return addThis;
698}
699
700
701
702
Lee Thomason56bdd022012-02-09 18:16:58 -0800703const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800704{
705 for( XMLNode* node=firstChild; node; node=node->next ) {
706 XMLElement* element = node->ToElement();
707 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800708 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800709 return element;
710 }
711 }
712 }
713 return 0;
714}
715
716
Lee Thomason56bdd022012-02-09 18:16:58 -0800717const XMLElement* XMLNode::LastChildElement( const char* value ) const
718{
719 for( XMLNode* node=lastChild; node; node=node->prev ) {
720 XMLElement* element = node->ToElement();
721 if ( element ) {
722 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
723 return element;
724 }
725 }
726 }
727 return 0;
728}
729
730
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800731const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
732{
733 for( XMLNode* element=this->next; element; element = element->next ) {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700734 if ( element->ToElement()
735 && (!value || XMLUtil::StringEqual( value, element->Value() )))
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800736 {
737 return element->ToElement();
738 }
739 }
740 return 0;
741}
742
743
744const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
745{
746 for( XMLNode* element=this->prev; element; element = element->prev ) {
747 if ( element->ToElement()
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700748 && (!value || XMLUtil::StringEqual( value, element->Value() )))
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800749 {
750 return element->ToElement();
751 }
752 }
753 return 0;
754}
755
756
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800757char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800758{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800759 // This is a recursive method, but thinking about it "at the current level"
760 // it is a pretty simple flat list:
761 // <foo/>
762 // <!-- comment -->
763 //
764 // With a special case:
765 // <foo>
766 // </foo>
767 // <!-- comment -->
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700768 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800769 // Where the closing element (/foo) *must* be the next thing after the opening
770 // element, and the names must match. BUT the tricky bit is that the closing
771 // element will be read by the child.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700772 //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800773 // 'endTag' is the end tag for this node, it is returned by a call to a child.
774 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800775
Lee Thomason67d61312012-01-24 16:01:51 -0800776 while( p && *p ) {
777 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800778
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800779 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800780 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800781 break;
782 }
783
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784 StrPair endTag;
785 p = node->ParseDeep( p, &endTag );
786 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800787 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800788 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800789 if ( !document->Error() ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700790 document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800791 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800792 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800793 }
794
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800795 // We read the end tag. Return it to the parent.
796 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
797 if ( parentEnd ) {
PKEuSc28ba3a2012-07-16 03:08:47 -0700798 *parentEnd = static_cast<XMLElement*>(node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800799 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800800 DELETE_NODE( node );
801 return p;
802 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800803
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800804 // Handle an end tag returned to this level.
805 // And handle a bunch of annoying errors.
806 XMLElement* ele = node->ToElement();
807 if ( ele ) {
808 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700809 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800810 p = 0;
811 }
812 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700813 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800814 p = 0;
815 }
816 else if ( !endTag.Empty() ) {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700817 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700818 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800819 p = 0;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800822 }
823 if ( p == 0 ) {
824 DELETE_NODE( node );
825 node = 0;
826 }
827 if ( node ) {
828 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800829 }
830 }
831 return 0;
832}
833
Lee Thomason5492a1c2012-01-23 15:32:10 -0800834// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800835char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800836{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800837 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800838 if ( this->CData() ) {
839 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800840 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700841 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800842 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800843 return p;
844 }
845 else {
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700846 int flags = document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
847 if ( document->WhitespaceMode() == COLLAPSE_WHITESPACE )
848 flags |= StrPair::COLLAPSE_WHITESPACE;
849
850 p = value.ParseText( p, "<", flags );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800851 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700852 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800853 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800854 if ( p && *p ) {
855 return p-1;
856 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800857 }
858 return 0;
859}
860
861
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800862XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
863{
864 if ( !doc ) {
865 doc = document;
866 }
867 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
868 text->SetCData( this->CData() );
869 return text;
870}
871
872
873bool XMLText::ShallowEqual( const XMLNode* compare ) const
874{
875 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
876}
877
878
Lee Thomason56bdd022012-02-09 18:16:58 -0800879bool XMLText::Accept( XMLVisitor* visitor ) const
880{
881 return visitor->Visit( *this );
882}
883
884
Lee Thomason3f57d272012-01-11 15:30:03 -0800885// --------- XMLComment ---------- //
886
Lee Thomasone4422302012-01-20 17:59:50 -0800887XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800888{
889}
890
891
Lee Thomasonce0763e2012-01-11 15:43:54 -0800892XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800893{
Lee Thomasond923c672012-01-23 08:44:25 -0800894 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800895}
896
897
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800898char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800899{
900 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800901 const char* start = p;
902 p = value.ParseText( p, "-->", StrPair::COMMENT );
903 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700904 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800905 }
906 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800907}
908
909
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800910XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
911{
912 if ( !doc ) {
913 doc = document;
914 }
915 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
916 return comment;
917}
918
919
920bool XMLComment::ShallowEqual( const XMLNode* compare ) const
921{
922 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
923}
924
925
Lee Thomason751da522012-02-10 08:50:51 -0800926bool XMLComment::Accept( XMLVisitor* visitor ) const
927{
928 return visitor->Visit( *this );
929}
Lee Thomason56bdd022012-02-09 18:16:58 -0800930
931
Lee Thomason50f97b22012-02-11 16:33:40 -0800932// --------- XMLDeclaration ---------- //
933
934XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
935{
936}
937
938
939XMLDeclaration::~XMLDeclaration()
940{
941 //printf( "~XMLDeclaration\n" );
942}
943
944
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800945char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800946{
947 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800948 const char* start = p;
949 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
950 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700951 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800952 }
953 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800954}
955
956
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
958{
959 if ( !doc ) {
960 doc = document;
961 }
962 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
963 return dec;
964}
965
966
967bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
968{
969 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
970}
971
972
973
Lee Thomason50f97b22012-02-11 16:33:40 -0800974bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
975{
976 return visitor->Visit( *this );
977}
978
979// --------- XMLUnknown ---------- //
980
981XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
982{
983}
984
985
986XMLUnknown::~XMLUnknown()
987{
988}
989
990
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800991char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800992{
993 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800994 const char* start = p;
995
996 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
997 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700998 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800999 }
1000 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001001}
1002
1003
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1005{
1006 if ( !doc ) {
1007 doc = document;
1008 }
1009 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1010 return text;
1011}
1012
1013
1014bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1015{
1016 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
1017}
1018
1019
Lee Thomason50f97b22012-02-11 16:33:40 -08001020bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1021{
1022 return visitor->Visit( *this );
1023}
1024
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001025// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001026char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001027{
Lee Thomason78a773d2012-07-02 10:10:19 -07001028 // Parse using the name rules: bug fix, was using ParseText before
1029 p = name.ParseName( p );
Lee Thomason22aead12012-01-23 13:29:35 -08001030 if ( !p || !*p ) return 0;
1031
Lee Thomason78a773d2012-07-02 10:10:19 -07001032 // Skip white space before =
1033 p = XMLUtil::SkipWhiteSpace( p );
1034 if ( !p || *p != '=' ) return 0;
1035
1036 ++p; // move up to opening quote
1037 p = XMLUtil::SkipWhiteSpace( p );
1038 if ( *p != '\"' && *p != '\'' ) return 0;
1039
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001040 char endTag[2] = { *p, 0 };
Lee Thomason78a773d2012-07-02 10:10:19 -07001041 ++p; // move past opening quote
1042
Lee Thomason6f381b72012-03-02 12:59:39 -08001043 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001044 return p;
1045}
1046
1047
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001048void XMLAttribute::SetName( const char* n )
1049{
1050 name.SetStr( n );
1051}
1052
1053
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001055{
Lee Thomason21be8822012-07-15 17:27:22 -07001056 if ( XMLUtil::ToInt( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001057 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001058 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001059}
1060
1061
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001062int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001063{
Lee Thomason21be8822012-07-15 17:27:22 -07001064 if ( XMLUtil::ToUnsigned( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001065 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001066 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001067}
1068
1069
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001071{
Lee Thomason21be8822012-07-15 17:27:22 -07001072 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001073 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001074 }
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001075 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001076}
1077
1078
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001079int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001080{
Lee Thomason21be8822012-07-15 17:27:22 -07001081 if ( XMLUtil::ToFloat( Value(), value ))
1082 return XML_NO_ERROR;
1083 return XML_WRONG_ATTRIBUTE_TYPE;
1084}
1085
1086
1087int XMLAttribute::QueryDoubleValue( double* value ) const
1088{
1089 if ( XMLUtil::ToDouble( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001090 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001091 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001092}
1093
1094
1095void XMLAttribute::SetAttribute( const char* v )
1096{
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001097 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001098}
1099
1100
Lee Thomason1ff38e02012-02-14 18:18:16 -08001101void XMLAttribute::SetAttribute( int v )
1102{
1103 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001104 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001105 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001106}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001107
1108
1109void XMLAttribute::SetAttribute( unsigned v )
1110{
1111 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001112 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001113 value.SetStr( buf );
1114}
1115
1116
1117void XMLAttribute::SetAttribute( bool v )
1118{
1119 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001120 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001121 value.SetStr( buf );
1122}
1123
1124void XMLAttribute::SetAttribute( double v )
1125{
1126 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001127 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001128 value.SetStr( buf );
1129}
1130
1131void XMLAttribute::SetAttribute( float v )
1132{
1133 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001134 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001135 value.SetStr( buf );
1136}
1137
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001138
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001139// --------- XMLElement ---------- //
1140XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001141 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001142 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001143{
1144}
1145
1146
1147XMLElement::~XMLElement()
1148{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001149 while( rootAttribute ) {
1150 XMLAttribute* next = rootAttribute->next;
1151 DELETE_ATTRIBUTE( rootAttribute );
1152 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001153 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001154}
1155
1156
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001157XMLAttribute* XMLElement::FindAttribute( const char* name )
1158{
1159 XMLAttribute* a = 0;
1160 for( a=rootAttribute; a; a = a->next ) {
1161 if ( XMLUtil::StringEqual( a->Name(), name ) )
1162 return a;
1163 }
1164 return 0;
1165}
1166
1167
1168const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1169{
1170 XMLAttribute* a = 0;
1171 for( a=rootAttribute; a; a = a->next ) {
1172 if ( XMLUtil::StringEqual( a->Name(), name ) )
1173 return a;
1174 }
1175 return 0;
1176}
1177
1178
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001179const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001180{
1181 const XMLAttribute* a = FindAttribute( name );
1182 if ( !a )
1183 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001184 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1185 return a->Value();
1186 return 0;
1187}
1188
1189
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001190const char* XMLElement::GetText() const
1191{
1192 if ( FirstChild() && FirstChild()->ToText() ) {
1193 return FirstChild()->ToText()->Value();
1194 }
1195 return 0;
1196}
1197
1198
Lee Thomason21be8822012-07-15 17:27:22 -07001199int XMLElement::QueryIntText( int* _value ) const
1200{
1201 if ( FirstChild() && FirstChild()->ToText() ) {
1202 const char* t = FirstChild()->ToText()->Value();
1203 if ( XMLUtil::ToInt( t, _value ) ) {
1204 return XML_SUCCESS;
1205 }
1206 return XML_CAN_NOT_CONVERT_TEXT;
1207 }
1208 return XML_NO_TEXT_NODE;
1209}
1210
1211
1212int XMLElement::QueryUnsignedText( unsigned* _value ) const
1213{
1214 if ( FirstChild() && FirstChild()->ToText() ) {
1215 const char* t = FirstChild()->ToText()->Value();
1216 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1217 return XML_SUCCESS;
1218 }
1219 return XML_CAN_NOT_CONVERT_TEXT;
1220 }
1221 return XML_NO_TEXT_NODE;
1222}
1223
1224
1225int XMLElement::QueryBoolText( bool* _value ) const
1226{
1227 if ( FirstChild() && FirstChild()->ToText() ) {
1228 const char* t = FirstChild()->ToText()->Value();
1229 if ( XMLUtil::ToBool( t, _value ) ) {
1230 return XML_SUCCESS;
1231 }
1232 return XML_CAN_NOT_CONVERT_TEXT;
1233 }
1234 return XML_NO_TEXT_NODE;
1235}
1236
1237
1238int XMLElement::QueryDoubleText( double* _value ) const
1239{
1240 if ( FirstChild() && FirstChild()->ToText() ) {
1241 const char* t = FirstChild()->ToText()->Value();
1242 if ( XMLUtil::ToDouble( t, _value ) ) {
1243 return XML_SUCCESS;
1244 }
1245 return XML_CAN_NOT_CONVERT_TEXT;
1246 }
1247 return XML_NO_TEXT_NODE;
1248}
1249
1250
1251int XMLElement::QueryFloatText( float* _value ) const
1252{
1253 if ( FirstChild() && FirstChild()->ToText() ) {
1254 const char* t = FirstChild()->ToText()->Value();
1255 if ( XMLUtil::ToFloat( t, _value ) ) {
1256 return XML_SUCCESS;
1257 }
1258 return XML_CAN_NOT_CONVERT_TEXT;
1259 }
1260 return XML_NO_TEXT_NODE;
1261}
1262
1263
1264
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001265XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1266{
Lee Thomason5e3803c2012-04-16 08:57:05 -07001267 XMLAttribute* last = 0;
1268 XMLAttribute* attrib = 0;
1269 for( attrib = rootAttribute;
1270 attrib;
1271 last = attrib, attrib = attrib->next )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001272 {
Lee Thomason5e3803c2012-04-16 08:57:05 -07001273 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1274 break;
1275 }
1276 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001277 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001278 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001279 attrib->memPool = &document->attributePool;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001280 if ( last ) {
1281 last->next = attrib;
1282 }
1283 else {
1284 rootAttribute = attrib;
1285 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001286 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001287 }
1288 return attrib;
1289}
1290
1291
U-Stream\Leeae25a442012-02-17 17:48:16 -08001292void XMLElement::DeleteAttribute( const char* name )
1293{
1294 XMLAttribute* prev = 0;
1295 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1296 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1297 if ( prev ) {
1298 prev->next = a->next;
1299 }
1300 else {
1301 rootAttribute = a->next;
1302 }
1303 DELETE_ATTRIBUTE( a );
1304 break;
1305 }
1306 prev = a;
1307 }
1308}
1309
1310
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001311char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001312{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001313 const char* start = p;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001314 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001315
1316 // Read the attributes.
1317 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001318 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001319 if ( !p || !(*p) ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001320 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001321 return 0;
1322 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001323
1324 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001325 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001326 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001327 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001328
Lee Thomason6f381b72012-03-02 12:59:39 -08001329 p = attrib->ParseDeep( p, document->ProcessEntities() );
Lee Thomasond6277762012-02-22 16:00:12 -08001330 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001331 DELETE_ATTRIBUTE( attrib );
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001332 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001333 return 0;
1334 }
Lee Thomason5e3803c2012-04-16 08:57:05 -07001335 // There is a minor bug here: if the attribute in the source xml
1336 // document is duplicated, it will not be detected and the
1337 // attribute will be doubly added. However, tracking the 'prevAttribute'
1338 // avoids re-scanning the attribute list. Preferring performance for
1339 // now, may reconsider in the future.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001340 if ( prevAttribute ) {
Lee Thomason5e3803c2012-04-16 08:57:05 -07001341 prevAttribute->next = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001342 }
1343 else {
1344 rootAttribute = attrib;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001345 }
Lee Thomason97088852012-04-18 11:39:42 -07001346 prevAttribute = attrib;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347 }
Lee Thomasone4422302012-01-20 17:59:50 -08001348 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001349 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001350 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351 return p+2; // done; sealed element.
1352 }
Lee Thomasone4422302012-01-20 17:59:50 -08001353 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001354 else if ( *p == '>' ) {
1355 ++p;
1356 break;
1357 }
Lee Thomasone4422302012-01-20 17:59:50 -08001358 else {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001359 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001360 return 0;
1361 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001362 }
Lee Thomason67d61312012-01-24 16:01:51 -08001363 return p;
1364}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001365
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001366
Lee Thomason67d61312012-01-24 16:01:51 -08001367//
1368// <ele></ele>
1369// <ele>foo<b>bar</b></ele>
1370//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001371char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001372{
1373 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001374 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001375 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001376
1377 // The closing element is the </element> form. It is
1378 // parsed just like a regular element then deleted from
1379 // the DOM.
1380 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001381 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001382 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001383 }
Lee Thomason67d61312012-01-24 16:01:51 -08001384
Lee Thomason56bdd022012-02-09 18:16:58 -08001385 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001386 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001387
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001388 p = ParseAttributes( p );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001389 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001390 return p;
1391
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001392 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001393 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001394}
1395
1396
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001397
1398XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1399{
1400 if ( !doc ) {
1401 doc = document;
1402 }
1403 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1404 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1405 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1406 }
1407 return element;
1408}
1409
1410
1411bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1412{
1413 const XMLElement* other = compare->ToElement();
1414 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1415
1416 const XMLAttribute* a=FirstAttribute();
1417 const XMLAttribute* b=other->FirstAttribute();
1418
1419 while ( a && b ) {
1420 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1421 return false;
1422 }
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001423 a = a->Next();
1424 b = b->Next();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001425 }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001426 if ( a || b ) {
1427 // different count
1428 return false;
1429 }
1430 return true;
1431 }
1432 return false;
1433}
1434
1435
Lee Thomason751da522012-02-10 08:50:51 -08001436bool XMLElement::Accept( XMLVisitor* visitor ) const
1437{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001438 if ( visitor->VisitEnter( *this, rootAttribute ) )
Lee Thomason751da522012-02-10 08:50:51 -08001439 {
1440 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1441 {
1442 if ( !node->Accept( visitor ) )
1443 break;
1444 }
1445 }
1446 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001447}
Lee Thomason56bdd022012-02-09 18:16:58 -08001448
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001449
Lee Thomason3f57d272012-01-11 15:30:03 -08001450// --------- XMLDocument ----------- //
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001451XMLDocument::XMLDocument( bool _processEntities, Whitespace _whitespace ) :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001452 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001453 writeBOM( false ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001454 processEntities( _processEntities ),
1455 errorID( 0 ),
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001456 whitespace( _whitespace ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001457 errorStr1( 0 ),
1458 errorStr2( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001459 charBuffer( 0 )
1460{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001461 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001462}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001463
1464
Lee Thomason3f57d272012-01-11 15:30:03 -08001465XMLDocument::~XMLDocument()
1466{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001467 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001468 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001469
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001470#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001471 textPool.Trace( "text" );
1472 elementPool.Trace( "element" );
1473 commentPool.Trace( "comment" );
1474 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001475#endif
1476
Lee Thomason455c9d42012-02-06 09:14:14 -08001477 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1478 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1479 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1480 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001481}
1482
1483
Lee Thomason18d68bd2012-01-26 18:17:26 -08001484void XMLDocument::InitDocument()
1485{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001486 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001487 errorStr1 = 0;
1488 errorStr2 = 0;
1489
1490 delete [] charBuffer;
1491 charBuffer = 0;
1492
1493}
1494
Lee Thomason3f57d272012-01-11 15:30:03 -08001495
Lee Thomason2c85a712012-01-31 08:24:24 -08001496XMLElement* XMLDocument::NewElement( const char* name )
1497{
Lee Thomasond1983222012-02-06 08:41:24 -08001498 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1499 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001500 ele->SetName( name );
1501 return ele;
1502}
1503
1504
Lee Thomason1ff38e02012-02-14 18:18:16 -08001505XMLComment* XMLDocument::NewComment( const char* str )
1506{
1507 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1508 comment->memPool = &commentPool;
1509 comment->SetValue( str );
1510 return comment;
1511}
1512
1513
1514XMLText* XMLDocument::NewText( const char* str )
1515{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001516 XMLText* text = new (textPool.Alloc()) XMLText( this );
1517 text->memPool = &textPool;
1518 text->SetValue( str );
1519 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001520}
1521
1522
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001523XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1524{
1525 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1526 dec->memPool = &commentPool;
Lee Thomasonf68c4382012-04-28 14:37:11 -07001527 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001528 return dec;
1529}
1530
1531
1532XMLUnknown* XMLDocument::NewUnknown( const char* str )
1533{
1534 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1535 unk->memPool = &commentPool;
1536 unk->SetValue( str );
1537 return unk;
1538}
1539
1540
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001541int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001542{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001543 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001544 InitDocument();
Martell186476c2012-09-06 16:41:46 +01001545 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001546
Martell186476c2012-09-06 16:41:46 +01001547 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1548 errno_t err = fopen_s(&fp, filename, "rb" );
1549 if ( !fp || err) {
1550 #else
1551 fp = fopen( filename, "rb" );
1552 if ( !fp) {
1553 #endif
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001554 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001555 return errorID;
1556 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001557 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001558 fclose( fp );
1559 return errorID;
1560}
1561
1562
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001563int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001564{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001565 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001566 InitDocument();
1567
1568 fseek( fp, 0, SEEK_END );
sniperbata5716b72012-10-11 15:22:28 +08001569 size_t size = ftell( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001570 fseek( fp, 0, SEEK_SET );
1571
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001572 if ( size == 0 ) {
1573 return errorID;
1574 }
1575
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001577 size_t read = fread( charBuffer, 1, size, fp );
1578 if ( read != size ) {
1579 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1580 return errorID;
1581 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001582
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001583 charBuffer[size] = 0;
1584
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001585 const char* p = charBuffer;
1586 p = XMLUtil::SkipWhiteSpace( p );
1587 p = XMLUtil::ReadBOM( p, &writeBOM );
1588 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001589 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001590 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001591 }
1592
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001593 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001594 return errorID;
1595}
1596
1597
Robert Reif312a20f2012-09-08 19:33:57 -04001598int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001599{
Martell186476c2012-09-06 16:41:46 +01001600 FILE* fp = 0;
1601 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1602 errno_t err = fopen_s(&fp, filename, "w" );
1603 if ( !fp || err) {
1604 #else
Lee Thomason3cd66ee2012-09-25 13:22:41 -07001605 fp = fopen( filename, "w" );
Martell186476c2012-09-06 16:41:46 +01001606 if ( !fp) {
1607 #endif
Lee Thomason7f7b1622012-03-24 12:49:03 -07001608 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001609 return errorID;
Lee Thomason7f7b1622012-03-24 12:49:03 -07001610 }
Robert Reif312a20f2012-09-08 19:33:57 -04001611 SaveFile(fp, compact);
Ken Miller81da1fb2012-04-09 23:32:26 -05001612 fclose( fp );
1613 return errorID;
1614}
1615
1616
Robert Reif312a20f2012-09-08 19:33:57 -04001617int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001618{
Robert Reif312a20f2012-09-08 19:33:57 -04001619 XMLPrinter stream( fp, compact );
Ken Miller81da1fb2012-04-09 23:32:26 -05001620 Print( &stream );
1621 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001622}
1623
Lee Thomason1ff38e02012-02-14 18:18:16 -08001624
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001625int XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001626{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001627 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001628 InitDocument();
1629
1630 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001631 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001632 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001633 }
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001634 if ( len == (size_t)(-1) ) {
1635 len = strlen( p );
1636 }
1637 charBuffer = new char[ len+1 ];
1638 memcpy( charBuffer, p, len );
1639 charBuffer[len] = 0;
1640
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001641 p = XMLUtil::SkipWhiteSpace( p );
1642 p = XMLUtil::ReadBOM( p, &writeBOM );
1643 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001644 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001645 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001646 }
1647
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001648 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001649 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001650}
1651
1652
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001653void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001654{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001655 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001656 if ( !streamer )
1657 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001658 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001659}
1660
1661
Lee Thomason67d61312012-01-24 16:01:51 -08001662void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1663{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001664 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001665 errorStr1 = str1;
1666 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001667}
1668
Lee Thomason5cae8972012-01-24 18:03:07 -08001669
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001670void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001671{
1672 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001673 static const int LEN = 20;
1674 char buf1[LEN] = { 0 };
1675 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001676
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001677 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001678 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001679 }
1680 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001681 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001682 }
1683
1684 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1685 errorID, buf1, buf2 );
1686 }
1687}
1688
1689
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001690XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
1691 elementJustOpened( false ),
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001692 firstElement( true ),
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001693 fp( file ),
1694 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001695 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001696 processEntities( true ),
1697 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001698{
Lee Thomason857b8682012-01-25 17:50:25 -08001699 for( int i=0; i<ENTITY_RANGE; ++i ) {
1700 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001701 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001702 }
1703 for( int i=0; i<NUM_ENTITIES; ++i ) {
1704 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1705 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001706 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001707 }
1708 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001709 restrictedEntityFlag[(int)'&'] = true;
1710 restrictedEntityFlag[(int)'<'] = true;
1711 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001712 buffer.Push( 0 );
1713}
1714
1715
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001716void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001717{
1718 va_list va;
1719 va_start( va, format );
1720
1721 if ( fp ) {
1722 vfprintf( fp, format, va );
1723 }
1724 else {
1725 // This seems brutally complex. Haven't figured out a better
1726 // way on windows.
1727 #ifdef _MSC_VER
1728 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001729 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001730 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001731 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001732 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001734 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001735 }
1736 }
1737 char* p = buffer.PushArr( len ) - 1;
1738 memcpy( p, accumulator.Mem(), len+1 );
1739 #else
1740 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001741 // Close out and re-start the va-args
1742 va_end( va );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001743 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001744 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001745 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001746 #endif
1747 }
1748 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001749}
1750
1751
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001752void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001753{
1754 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001755 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001756 }
1757}
1758
1759
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001760void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001761{
Lee Thomason951d8832012-01-26 08:47:06 -08001762 // Look for runs of bytes between entities to print.
1763 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001764 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001765
Lee Thomason6f381b72012-03-02 12:59:39 -08001766 if ( processEntities ) {
1767 while ( *q ) {
1768 // Remember, char is sometimes signed. (How many times has that bitten me?)
1769 if ( *q > 0 && *q < ENTITY_RANGE ) {
1770 // Check for entities. If one is found, flush
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001771 // the stream up until the entity, write the
Lee Thomason6f381b72012-03-02 12:59:39 -08001772 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001773 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001774 while ( p < q ) {
1775 Print( "%c", *p );
1776 ++p;
1777 }
1778 for( int i=0; i<NUM_ENTITIES; ++i ) {
1779 if ( entities[i].value == *q ) {
1780 Print( "&%s;", entities[i].pattern );
1781 break;
1782 }
1783 }
Lee Thomason951d8832012-01-26 08:47:06 -08001784 ++p;
1785 }
Lee Thomason951d8832012-01-26 08:47:06 -08001786 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001787 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001788 }
Lee Thomason951d8832012-01-26 08:47:06 -08001789 }
1790 // Flush the remaining string. This will be the entire
1791 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001792 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001793 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001794 }
Lee Thomason857b8682012-01-25 17:50:25 -08001795}
1796
U-Stream\Leeae25a442012-02-17 17:48:16 -08001797
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001798void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001799{
1800 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1801 if ( writeBOM ) {
1802 Print( "%s", bom );
1803 }
1804 if ( writeDec ) {
1805 PushDeclaration( "xml version=\"1.0\"" );
1806 }
1807}
1808
1809
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001810void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001811{
1812 if ( elementJustOpened ) {
1813 SealElement();
1814 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001815 stack.Push( name );
1816
sniperbat25900882012-05-28 17:22:07 +08001817 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001818 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001819 PrintSpace( depth );
1820 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001821
U-Stream\Leeae25a442012-02-17 17:48:16 -08001822 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001823 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001824 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001825 ++depth;
1826}
1827
1828
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001829void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001830{
1831 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001832 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001834 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001835}
1836
1837
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001838void XMLPrinter::PushAttribute( const char* name, int v )
1839{
1840 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001841 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001842 PushAttribute( name, buf );
1843}
1844
1845
1846void XMLPrinter::PushAttribute( const char* name, unsigned v )
1847{
1848 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001849 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001850 PushAttribute( name, buf );
1851}
1852
1853
1854void XMLPrinter::PushAttribute( const char* name, bool v )
1855{
1856 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001857 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001858 PushAttribute( name, buf );
1859}
1860
1861
1862void XMLPrinter::PushAttribute( const char* name, double v )
1863{
1864 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001865 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001866 PushAttribute( name, buf );
1867}
1868
1869
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001870void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001871{
1872 --depth;
1873 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001874
1875 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001876 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001877 }
1878 else {
sniperbat25900882012-05-28 17:22:07 +08001879 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001880 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001881 PrintSpace( depth );
1882 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001883 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001884 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001885
1886 if ( textDepth == depth )
1887 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001888 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001889 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001890 elementJustOpened = false;
1891}
1892
1893
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001894void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001895{
1896 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001897 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001898}
1899
1900
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001901void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001902{
Lee Thomason56bdd022012-02-09 18:16:58 -08001903 textDepth = depth-1;
1904
Lee Thomason5cae8972012-01-24 18:03:07 -08001905 if ( elementJustOpened ) {
1906 SealElement();
1907 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001908 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001909 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001910 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001911 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912 }
1913 else {
1914 PrintString( text, true );
1915 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001916}
1917
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001918void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001919{
1920 char buf[BUF_SIZE];
1921 XMLUtil::ToStr( value, buf, BUF_SIZE );
1922 PushText( buf, false );
1923}
1924
1925
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001926void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001927{
1928 char buf[BUF_SIZE];
1929 XMLUtil::ToStr( value, buf, BUF_SIZE );
1930 PushText( buf, false );
1931}
1932
1933
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001934void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001935{
1936 char buf[BUF_SIZE];
1937 XMLUtil::ToStr( value, buf, BUF_SIZE );
1938 PushText( buf, false );
1939}
1940
1941
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001942void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001943{
1944 char buf[BUF_SIZE];
1945 XMLUtil::ToStr( value, buf, BUF_SIZE );
1946 PushText( buf, false );
1947}
1948
1949
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001950void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001951{
1952 char buf[BUF_SIZE];
1953 XMLUtil::ToStr( value, buf, BUF_SIZE );
1954 PushText( buf, false );
1955}
1956
Lee Thomason5cae8972012-01-24 18:03:07 -08001957
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001958void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001959{
1960 if ( elementJustOpened ) {
1961 SealElement();
1962 }
sniperbat25900882012-05-28 17:22:07 +08001963 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001964 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001965 PrintSpace( depth );
1966 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001967 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001968 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001969}
Lee Thomason751da522012-02-10 08:50:51 -08001970
1971
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001972void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001973{
1974 if ( elementJustOpened ) {
1975 SealElement();
1976 }
sniperbat25900882012-05-28 17:22:07 +08001977 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001978 Print( "\n" );
1979 PrintSpace( depth );
1980 }
1981 firstElement = false;
1982 Print( "<?%s?>", value );
1983}
1984
1985
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001986void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001987{
1988 if ( elementJustOpened ) {
1989 SealElement();
1990 }
sniperbat25900882012-05-28 17:22:07 +08001991 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001992 Print( "\n" );
1993 PrintSpace( depth );
1994 }
1995 firstElement = false;
1996 Print( "<!%s>", value );
1997}
1998
1999
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002000bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002001{
Lee Thomason6f381b72012-03-02 12:59:39 -08002002 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002003 if ( doc.HasBOM() ) {
2004 PushHeader( true, false );
2005 }
2006 return true;
2007}
2008
2009
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002010bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002011{
2012 OpenElement( element.Name() );
2013 while ( attribute ) {
2014 PushAttribute( attribute->Name(), attribute->Value() );
2015 attribute = attribute->Next();
2016 }
2017 return true;
2018}
2019
2020
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002021bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002022{
2023 CloseElement();
2024 return true;
2025}
2026
2027
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002028bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002029{
Lee Thomasond6277762012-02-22 16:00:12 -08002030 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08002031 return true;
2032}
2033
2034
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002035bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002036{
2037 PushComment( comment.Value() );
2038 return true;
2039}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002040
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002041bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002042{
2043 PushDeclaration( declaration.Value() );
2044 return true;
2045}
2046
2047
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002048bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002049{
2050 PushUnknown( unknown.Value() );
2051 return true;
2052}