blob: b20d9f0c8e4ba427ced70c6e3cfba3942451397e [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;
73static const Entity entities[NUM_ENTITIES] =
74{
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;
126 }
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
139 if ( !XMLUtil::IsAlpha( *p ) ) {
140 return 0;
141 }
142
143 while( *p && (
144 XMLUtil::IsAlphaNum( (unsigned char) *p )
145 || *p == '_'
146 || *p == '-'
147 || *p == '.'
148 || *p == ':' ))
149 {
150 ++p;
151 }
152
153 if ( p > start ) {
154 Set( start, p, 0 );
155 return p;
156 }
157 return 0;
158}
159
160
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161void StrPair::CollapseWhitespace()
162{
163 // Trim leading space.
164 start = XMLUtil::SkipWhiteSpace( start );
165
166 if ( start && *start ) {
167 char* p = start; // the read pointer
168 char* q = start; // the write pointer
169
170 while( *p ) {
171 if ( XMLUtil::IsWhiteSpace( *p )) {
172 p = XMLUtil::SkipWhiteSpace( p );
173 if ( *p == 0 )
174 break; // don't write to q; this trims the trailing space.
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
189 if ( flags & NEEDS_FLUSH ) {
190 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800191 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason8ee79892012-01-25 17:44:30 -0800193 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800194 char* p = start; // the read pointer
195 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
197 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800198 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800208 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800209 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800210 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800217 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800218 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800219 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
224
225 if ( *(p+1) == '#' ) {
226 char buf[10] = { 0 };
227 int len;
228 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
229 for( int i=0; i<len; ++i ) {
230 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800231 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800232 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800233 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800234 else {
PKEuSc28ba3a2012-07-16 03:08:47 -0700235 int i=0;
236 for(; i<NUM_ENTITIES; ++i ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800237 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
238 && *(p+entities[i].length+1) == ';' )
239 {
240 // Found an entity convert;
241 *q = entities[i].value;
242 ++q;
243 p += entities[i].length + 2;
244 break;
245 }
246 }
247 if ( i == NUM_ENTITIES ) {
248 // fixme: treat as error?
249 ++p;
250 ++q;
251 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800252 }
253 }
Lee Thomasone4422302012-01-20 17:59:50 -0800254 else {
255 *q = *p;
256 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800257 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800258 }
259 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800260 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800261 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700262 // The loop below has plenty going on, and this
263 // is a less useful mode. Break it out.
264 if ( flags & COLLAPSE_WHITESPACE ) {
265 CollapseWhitespace();
266 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800267 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800268 }
269 return start;
270}
271
Lee Thomason2c85a712012-01-31 08:24:24 -0800272
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800274
Lee Thomason56bdd022012-02-09 18:16:58 -0800275// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800276
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800277const char* XMLUtil::ReadBOM( const char* p, bool* bom )
278{
279 *bom = false;
280 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
281 // Check for BOM:
282 if ( *(pu+0) == TIXML_UTF_LEAD_0
283 && *(pu+1) == TIXML_UTF_LEAD_1
284 && *(pu+2) == TIXML_UTF_LEAD_2 )
285 {
286 *bom = true;
287 p += 3;
288 }
289 return p;
290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
298
299 if (input < 0x80)
300 *length = 1;
301 else if ( input < 0x800 )
302 *length = 2;
303 else if ( input < 0x10000 )
304 *length = 3;
305 else if ( input < 0x200000 )
306 *length = 4;
307 else
308 { *length = 0; return; } // This code won't covert this correctly anyway.
309
310 output += *length;
311
312 // Scary scary fall throughs.
313 switch (*length)
314 {
315 case 4:
316 --output;
317 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
318 input >>= 6;
319 case 3:
320 --output;
321 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
322 input >>= 6;
323 case 2:
324 --output;
325 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
326 input >>= 6;
327 case 1:
328 --output;
329 *output = (char)(input | FIRST_BYTE_MARK[*length]);
330 }
331}
332
333
334const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
335{
336 // Presume an entity, and pull it out.
337 *length = 0;
338
339 if ( *(p+1) == '#' && *(p+2) )
340 {
341 unsigned long ucs = 0;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200342 ptrdiff_t delta = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800343 unsigned mult = 1;
344
345 if ( *(p+2) == 'x' )
346 {
347 // Hexadecimal.
348 if ( !*(p+3) ) return 0;
349
350 const char* q = p+3;
351 q = strchr( q, ';' );
352
353 if ( !q || !*q ) return 0;
354
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200355 delta = q-p;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356 --q;
357
358 while ( *q != 'x' )
359 {
360 if ( *q >= '0' && *q <= '9' )
361 ucs += mult * (*q - '0');
362 else if ( *q >= 'a' && *q <= 'f' )
363 ucs += mult * (*q - 'a' + 10);
364 else if ( *q >= 'A' && *q <= 'F' )
365 ucs += mult * (*q - 'A' + 10 );
366 else
367 return 0;
368 mult *= 16;
369 --q;
370 }
371 }
372 else
373 {
374 // Decimal.
375 if ( !*(p+2) ) return 0;
376
377 const char* q = p+2;
378 q = strchr( q, ';' );
379
380 if ( !q || !*q ) return 0;
381
382 delta = q-p;
383 --q;
384
385 while ( *q != '#' )
386 {
387 if ( *q >= '0' && *q <= '9' )
388 ucs += mult * (*q - '0');
389 else
390 return 0;
391 mult *= 10;
392 --q;
393 }
394 }
395 // convert the UCS to UTF-8
396 ConvertUTF32ToUTF8( ucs, value, length );
397 return p + delta + 1;
398 }
399 return p+1;
400}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800401
402
Lee Thomason21be8822012-07-15 17:27:22 -0700403void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
404{
405 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
406}
407
408
409void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
410{
411 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
412}
413
414
415void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
416{
417 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
418}
419
420
421void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
422{
423 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
424}
425
426
427void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
428{
429 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
430}
431
432
433bool XMLUtil::ToInt( const char* str, int* value )
434{
435 if ( TIXML_SSCANF( str, "%d", value ) == 1 )
436 return true;
437 return false;
438}
439
440bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
441{
442 if ( TIXML_SSCANF( str, "%u", value ) == 1 )
443 return true;
444 return false;
445}
446
447bool XMLUtil::ToBool( const char* str, bool* value )
448{
449 int ival = 0;
450 if ( ToInt( str, &ival )) {
451 *value = (ival==0) ? false : true;
452 return true;
453 }
454 if ( StringEqual( str, "true" ) ) {
455 *value = true;
456 return true;
457 }
458 else if ( StringEqual( str, "false" ) ) {
459 *value = false;
460 return true;
461 }
462 return false;
463}
464
465
466bool XMLUtil::ToFloat( const char* str, float* value )
467{
468 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
469 return true;
470 }
471 return false;
472}
473
474bool XMLUtil::ToDouble( const char* str, double* value )
475{
476 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
477 return true;
478 }
479 return false;
480}
481
482
Lee Thomasond1983222012-02-06 08:41:24 -0800483char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800484{
485 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800486 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800487 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800488 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800489 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800490 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800491 }
492
493 // What is this thing?
494 // - Elements start with a letter or underscore, but xml is reserved.
495 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800496 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800497 // - Everthing else is unknown to tinyxml.
498 //
499
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800500 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501 static const char* commentHeader = { "<!--" };
502 static const char* dtdHeader = { "<!" };
503 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800504 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800506 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800507 static const int commentHeaderLen = 4;
508 static const int dtdHeaderLen = 2;
509 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800510 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800512#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800513#pragma warning ( push )
514#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800515#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800516 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
517 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800518#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800519#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800520#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800521 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
522 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
523 returnNode->memPool = &commentPool;
524 p += xmlHeaderLen;
525 }
526 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800527 returnNode = new (commentPool.Alloc()) XMLComment( this );
528 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800529 p += commentHeaderLen;
530 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800531 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
532 XMLText* text = new (textPool.Alloc()) XMLText( this );
533 returnNode = text;
534 returnNode->memPool = &textPool;
535 p += cdataHeaderLen;
536 text->SetCData( true );
537 }
538 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
539 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
540 returnNode->memPool = &commentPool;
541 p += dtdHeaderLen;
542 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800543 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800544 returnNode = new (elementPool.Alloc()) XMLElement( this );
545 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800546 p += elementHeaderLen;
547 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800548 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800549 returnNode = new (textPool.Alloc()) XMLText( this );
550 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800551 p = start; // Back it up, all the text counts.
552 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800553
554 *node = returnNode;
555 return p;
556}
557
558
Lee Thomason751da522012-02-10 08:50:51 -0800559bool XMLDocument::Accept( XMLVisitor* visitor ) const
560{
561 if ( visitor->VisitEnter( *this ) )
562 {
563 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
564 {
565 if ( !node->Accept( visitor ) )
566 break;
567 }
568 }
569 return visitor->VisitExit( *this );
570}
Lee Thomason56bdd022012-02-09 18:16:58 -0800571
572
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573// --------- XMLNode ----------- //
574
575XMLNode::XMLNode( XMLDocument* doc ) :
576 document( doc ),
577 parent( 0 ),
578 firstChild( 0 ), lastChild( 0 ),
579 prev( 0 ), next( 0 )
580{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800581}
582
583
584XMLNode::~XMLNode()
585{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800586 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800587 if ( parent ) {
588 parent->Unlink( this );
589 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800590}
591
592
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800593void XMLNode::SetValue( const char* str, bool staticMem )
594{
595 if ( staticMem )
596 value.SetInternedStr( str );
597 else
598 value.SetStr( str );
599}
600
601
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800602void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800603{
Lee Thomasond923c672012-01-23 08:44:25 -0800604 while( firstChild ) {
605 XMLNode* node = firstChild;
606 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800607
Lee Thomason43f59302012-02-06 18:18:11 -0800608 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800609 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800610 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800611}
612
613
614void XMLNode::Unlink( XMLNode* child )
615{
616 TIXMLASSERT( child->parent == this );
617 if ( child == firstChild )
618 firstChild = firstChild->next;
619 if ( child == lastChild )
620 lastChild = lastChild->prev;
621
622 if ( child->prev ) {
623 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800624 }
Lee Thomasond923c672012-01-23 08:44:25 -0800625 if ( child->next ) {
626 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627 }
Lee Thomasond923c672012-01-23 08:44:25 -0800628 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800629}
630
631
U-Stream\Leeae25a442012-02-17 17:48:16 -0800632void XMLNode::DeleteChild( XMLNode* node )
633{
634 TIXMLASSERT( node->parent == this );
635 DELETE_NODE( node );
636}
637
638
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800639XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
640{
641 if ( lastChild ) {
642 TIXMLASSERT( firstChild );
643 TIXMLASSERT( lastChild->next == 0 );
644 lastChild->next = addThis;
645 addThis->prev = lastChild;
646 lastChild = addThis;
647
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800648 addThis->next = 0;
649 }
650 else {
651 TIXMLASSERT( firstChild == 0 );
652 firstChild = lastChild = addThis;
653
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654 addThis->prev = 0;
655 addThis->next = 0;
656 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800657 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658 return addThis;
659}
660
661
Lee Thomason1ff38e02012-02-14 18:18:16 -0800662XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
663{
664 if ( firstChild ) {
665 TIXMLASSERT( lastChild );
666 TIXMLASSERT( firstChild->prev == 0 );
667
668 firstChild->prev = addThis;
669 addThis->next = firstChild;
670 firstChild = addThis;
671
Lee Thomason1ff38e02012-02-14 18:18:16 -0800672 addThis->prev = 0;
673 }
674 else {
675 TIXMLASSERT( lastChild == 0 );
676 firstChild = lastChild = addThis;
677
Lee Thomason1ff38e02012-02-14 18:18:16 -0800678 addThis->prev = 0;
679 addThis->next = 0;
680 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800681 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682 return addThis;
683}
684
685
686XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
687{
688 TIXMLASSERT( afterThis->parent == this );
689 if ( afterThis->parent != this )
690 return 0;
691
692 if ( afterThis->next == 0 ) {
693 // The last node or the only node.
694 return InsertEndChild( addThis );
695 }
696 addThis->prev = afterThis;
697 addThis->next = afterThis->next;
698 afterThis->next->prev = addThis;
699 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800700 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701 return addThis;
702}
703
704
705
706
Lee Thomason56bdd022012-02-09 18:16:58 -0800707const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800708{
709 for( XMLNode* node=firstChild; node; node=node->next ) {
710 XMLElement* element = node->ToElement();
711 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800712 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800713 return element;
714 }
715 }
716 }
717 return 0;
718}
719
720
Lee Thomason56bdd022012-02-09 18:16:58 -0800721const XMLElement* XMLNode::LastChildElement( const char* value ) const
722{
723 for( XMLNode* node=lastChild; node; node=node->prev ) {
724 XMLElement* element = node->ToElement();
725 if ( element ) {
726 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
727 return element;
728 }
729 }
730 }
731 return 0;
732}
733
734
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800735const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
736{
737 for( XMLNode* element=this->next; element; element = element->next ) {
738 if ( element->ToElement()
739 && (!value || XMLUtil::StringEqual( value, element->Value() )))
740 {
741 return element->ToElement();
742 }
743 }
744 return 0;
745}
746
747
748const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
749{
750 for( XMLNode* element=this->prev; element; element = element->prev ) {
751 if ( element->ToElement()
752 && (!value || XMLUtil::StringEqual( value, element->Value() )))
753 {
754 return element->ToElement();
755 }
756 }
757 return 0;
758}
759
760
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800761char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800762{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800763 // This is a recursive method, but thinking about it "at the current level"
764 // it is a pretty simple flat list:
765 // <foo/>
766 // <!-- comment -->
767 //
768 // With a special case:
769 // <foo>
770 // </foo>
771 // <!-- comment -->
772 //
773 // Where the closing element (/foo) *must* be the next thing after the opening
774 // element, and the names must match. BUT the tricky bit is that the closing
775 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800776 //
777 // 'endTag' is the end tag for this node, it is returned by a call to a child.
778 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800779
Lee Thomason67d61312012-01-24 16:01:51 -0800780 while( p && *p ) {
781 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800782
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800783 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800784 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800785 break;
786 }
787
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800788 StrPair endTag;
789 p = node->ParseDeep( p, &endTag );
790 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800791 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800792 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800793 if ( !document->Error() ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700794 document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800795 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800796 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800797 }
798
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800799 // We read the end tag. Return it to the parent.
800 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
801 if ( parentEnd ) {
PKEuSc28ba3a2012-07-16 03:08:47 -0700802 *parentEnd = static_cast<XMLElement*>(node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800803 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800804 DELETE_NODE( node );
805 return p;
806 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800807
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800808 // Handle an end tag returned to this level.
809 // And handle a bunch of annoying errors.
810 XMLElement* ele = node->ToElement();
811 if ( ele ) {
812 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() && ele->ClosingType() != XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700817 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800818 p = 0;
819 }
820 else if ( !endTag.Empty() ) {
821 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700822 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800823 p = 0;
824 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800825 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800826 }
827 if ( p == 0 ) {
828 DELETE_NODE( node );
829 node = 0;
830 }
831 if ( node ) {
832 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800833 }
834 }
835 return 0;
836}
837
Lee Thomason5492a1c2012-01-23 15:32:10 -0800838// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800839char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800840{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800841 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800842 if ( this->CData() ) {
843 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800844 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700845 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800846 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800847 return p;
848 }
849 else {
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700850 int flags = document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
851 if ( document->WhitespaceMode() == COLLAPSE_WHITESPACE )
852 flags |= StrPair::COLLAPSE_WHITESPACE;
853
854 p = value.ParseText( p, "<", flags );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800855 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700856 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800857 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800858 if ( p && *p ) {
859 return p-1;
860 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800861 }
862 return 0;
863}
864
865
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800866XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
867{
868 if ( !doc ) {
869 doc = document;
870 }
871 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
872 text->SetCData( this->CData() );
873 return text;
874}
875
876
877bool XMLText::ShallowEqual( const XMLNode* compare ) const
878{
879 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
880}
881
882
Lee Thomason56bdd022012-02-09 18:16:58 -0800883bool XMLText::Accept( XMLVisitor* visitor ) const
884{
885 return visitor->Visit( *this );
886}
887
888
Lee Thomason3f57d272012-01-11 15:30:03 -0800889// --------- XMLComment ---------- //
890
Lee Thomasone4422302012-01-20 17:59:50 -0800891XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800892{
893}
894
895
Lee Thomasonce0763e2012-01-11 15:43:54 -0800896XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800897{
Lee Thomasond923c672012-01-23 08:44:25 -0800898 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800899}
900
901
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800902char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800903{
904 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800905 const char* start = p;
906 p = value.ParseText( p, "-->", StrPair::COMMENT );
907 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700908 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800909 }
910 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800911}
912
913
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800914XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
915{
916 if ( !doc ) {
917 doc = document;
918 }
919 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
920 return comment;
921}
922
923
924bool XMLComment::ShallowEqual( const XMLNode* compare ) const
925{
926 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
927}
928
929
Lee Thomason751da522012-02-10 08:50:51 -0800930bool XMLComment::Accept( XMLVisitor* visitor ) const
931{
932 return visitor->Visit( *this );
933}
Lee Thomason56bdd022012-02-09 18:16:58 -0800934
935
Lee Thomason50f97b22012-02-11 16:33:40 -0800936// --------- XMLDeclaration ---------- //
937
938XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
939{
940}
941
942
943XMLDeclaration::~XMLDeclaration()
944{
945 //printf( "~XMLDeclaration\n" );
946}
947
948
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800949char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800950{
951 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800952 const char* start = p;
953 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
954 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700955 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800956 }
957 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800958}
959
960
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
962{
963 if ( !doc ) {
964 doc = document;
965 }
966 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
967 return dec;
968}
969
970
971bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
972{
973 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
974}
975
976
977
Lee Thomason50f97b22012-02-11 16:33:40 -0800978bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
979{
980 return visitor->Visit( *this );
981}
982
983// --------- XMLUnknown ---------- //
984
985XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
986{
987}
988
989
990XMLUnknown::~XMLUnknown()
991{
992}
993
994
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800995char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800996{
997 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800998 const char* start = p;
999
1000 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1001 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001002 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001003 }
1004 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001005}
1006
1007
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001008XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1009{
1010 if ( !doc ) {
1011 doc = document;
1012 }
1013 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1014 return text;
1015}
1016
1017
1018bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1019{
1020 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
1021}
1022
1023
Lee Thomason50f97b22012-02-11 16:33:40 -08001024bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1025{
1026 return visitor->Visit( *this );
1027}
1028
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001029// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001030char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001031{
Lee Thomason78a773d2012-07-02 10:10:19 -07001032 // Parse using the name rules: bug fix, was using ParseText before
1033 p = name.ParseName( p );
Lee Thomason22aead12012-01-23 13:29:35 -08001034 if ( !p || !*p ) return 0;
1035
Lee Thomason78a773d2012-07-02 10:10:19 -07001036 // Skip white space before =
1037 p = XMLUtil::SkipWhiteSpace( p );
1038 if ( !p || *p != '=' ) return 0;
1039
1040 ++p; // move up to opening quote
1041 p = XMLUtil::SkipWhiteSpace( p );
1042 if ( *p != '\"' && *p != '\'' ) return 0;
1043
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001044 char endTag[2] = { *p, 0 };
Lee Thomason78a773d2012-07-02 10:10:19 -07001045 ++p; // move past opening quote
1046
Lee Thomason6f381b72012-03-02 12:59:39 -08001047 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001048 return p;
1049}
1050
1051
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001052void XMLAttribute::SetName( const char* n )
1053{
1054 name.SetStr( n );
1055}
1056
1057
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001059{
Lee Thomason21be8822012-07-15 17:27:22 -07001060 if ( XMLUtil::ToInt( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001061 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001062 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001063}
1064
1065
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001066int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001067{
Lee Thomason21be8822012-07-15 17:27:22 -07001068 if ( XMLUtil::ToUnsigned( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001069 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001070 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001071}
1072
1073
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001074int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001075{
Lee Thomason21be8822012-07-15 17:27:22 -07001076 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001077 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001078 }
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001079 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001080}
1081
1082
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001083int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001084{
Lee Thomason21be8822012-07-15 17:27:22 -07001085 if ( XMLUtil::ToFloat( Value(), value ))
1086 return XML_NO_ERROR;
1087 return XML_WRONG_ATTRIBUTE_TYPE;
1088}
1089
1090
1091int XMLAttribute::QueryDoubleValue( double* value ) const
1092{
1093 if ( XMLUtil::ToDouble( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001094 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001095 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001096}
1097
1098
1099void XMLAttribute::SetAttribute( const char* v )
1100{
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001101 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001102}
1103
1104
Lee Thomason1ff38e02012-02-14 18:18:16 -08001105void XMLAttribute::SetAttribute( int v )
1106{
1107 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001108 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001109 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001110}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001111
1112
1113void XMLAttribute::SetAttribute( unsigned v )
1114{
1115 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001116 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001117 value.SetStr( buf );
1118}
1119
1120
1121void XMLAttribute::SetAttribute( bool v )
1122{
1123 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001124 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001125 value.SetStr( buf );
1126}
1127
1128void XMLAttribute::SetAttribute( double v )
1129{
1130 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001131 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001132 value.SetStr( buf );
1133}
1134
1135void XMLAttribute::SetAttribute( float v )
1136{
1137 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001138 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001139 value.SetStr( buf );
1140}
1141
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001142
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001143// --------- XMLElement ---------- //
1144XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001145 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001146 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001147{
1148}
1149
1150
1151XMLElement::~XMLElement()
1152{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001153 while( rootAttribute ) {
1154 XMLAttribute* next = rootAttribute->next;
1155 DELETE_ATTRIBUTE( rootAttribute );
1156 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001157 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001158}
1159
1160
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001161XMLAttribute* XMLElement::FindAttribute( const char* name )
1162{
1163 XMLAttribute* a = 0;
1164 for( a=rootAttribute; a; a = a->next ) {
1165 if ( XMLUtil::StringEqual( a->Name(), name ) )
1166 return a;
1167 }
1168 return 0;
1169}
1170
1171
1172const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1173{
1174 XMLAttribute* a = 0;
1175 for( a=rootAttribute; a; a = a->next ) {
1176 if ( XMLUtil::StringEqual( a->Name(), name ) )
1177 return a;
1178 }
1179 return 0;
1180}
1181
1182
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001183const char* XMLElement::Attribute( const char* name, const char* value ) const
1184{
1185 const XMLAttribute* a = FindAttribute( name );
1186 if ( !a )
1187 return 0;
1188 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1189 return a->Value();
1190 return 0;
1191}
1192
1193
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001194const char* XMLElement::GetText() const
1195{
1196 if ( FirstChild() && FirstChild()->ToText() ) {
1197 return FirstChild()->ToText()->Value();
1198 }
1199 return 0;
1200}
1201
1202
Lee Thomason21be8822012-07-15 17:27:22 -07001203int XMLElement::QueryIntText( int* _value ) const
1204{
1205 if ( FirstChild() && FirstChild()->ToText() ) {
1206 const char* t = FirstChild()->ToText()->Value();
1207 if ( XMLUtil::ToInt( t, _value ) ) {
1208 return XML_SUCCESS;
1209 }
1210 return XML_CAN_NOT_CONVERT_TEXT;
1211 }
1212 return XML_NO_TEXT_NODE;
1213}
1214
1215
1216int XMLElement::QueryUnsignedText( unsigned* _value ) const
1217{
1218 if ( FirstChild() && FirstChild()->ToText() ) {
1219 const char* t = FirstChild()->ToText()->Value();
1220 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1221 return XML_SUCCESS;
1222 }
1223 return XML_CAN_NOT_CONVERT_TEXT;
1224 }
1225 return XML_NO_TEXT_NODE;
1226}
1227
1228
1229int XMLElement::QueryBoolText( bool* _value ) const
1230{
1231 if ( FirstChild() && FirstChild()->ToText() ) {
1232 const char* t = FirstChild()->ToText()->Value();
1233 if ( XMLUtil::ToBool( t, _value ) ) {
1234 return XML_SUCCESS;
1235 }
1236 return XML_CAN_NOT_CONVERT_TEXT;
1237 }
1238 return XML_NO_TEXT_NODE;
1239}
1240
1241
1242int XMLElement::QueryDoubleText( double* _value ) const
1243{
1244 if ( FirstChild() && FirstChild()->ToText() ) {
1245 const char* t = FirstChild()->ToText()->Value();
1246 if ( XMLUtil::ToDouble( t, _value ) ) {
1247 return XML_SUCCESS;
1248 }
1249 return XML_CAN_NOT_CONVERT_TEXT;
1250 }
1251 return XML_NO_TEXT_NODE;
1252}
1253
1254
1255int XMLElement::QueryFloatText( float* _value ) const
1256{
1257 if ( FirstChild() && FirstChild()->ToText() ) {
1258 const char* t = FirstChild()->ToText()->Value();
1259 if ( XMLUtil::ToFloat( t, _value ) ) {
1260 return XML_SUCCESS;
1261 }
1262 return XML_CAN_NOT_CONVERT_TEXT;
1263 }
1264 return XML_NO_TEXT_NODE;
1265}
1266
1267
1268
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001269XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1270{
Lee Thomason5e3803c2012-04-16 08:57:05 -07001271 XMLAttribute* last = 0;
1272 XMLAttribute* attrib = 0;
1273 for( attrib = rootAttribute;
1274 attrib;
1275 last = attrib, attrib = attrib->next )
1276 {
1277 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1278 break;
1279 }
1280 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001281 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001282 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001283 attrib->memPool = &document->attributePool;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001284 if ( last ) {
1285 last->next = attrib;
1286 }
1287 else {
1288 rootAttribute = attrib;
1289 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001290 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001291 }
1292 return attrib;
1293}
1294
1295
U-Stream\Leeae25a442012-02-17 17:48:16 -08001296void XMLElement::DeleteAttribute( const char* name )
1297{
1298 XMLAttribute* prev = 0;
1299 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1300 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1301 if ( prev ) {
1302 prev->next = a->next;
1303 }
1304 else {
1305 rootAttribute = a->next;
1306 }
1307 DELETE_ATTRIBUTE( a );
1308 break;
1309 }
1310 prev = a;
1311 }
1312}
1313
1314
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001315char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001316{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001317 const char* start = p;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001318 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001319
1320 // Read the attributes.
1321 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001322 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001323 if ( !p || !(*p) ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001324 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001325 return 0;
1326 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001327
1328 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001329 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001330 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001331 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001332
Lee Thomason6f381b72012-03-02 12:59:39 -08001333 p = attrib->ParseDeep( p, document->ProcessEntities() );
Lee Thomasond6277762012-02-22 16:00:12 -08001334 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001335 DELETE_ATTRIBUTE( attrib );
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001336 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001337 return 0;
1338 }
Lee Thomason5e3803c2012-04-16 08:57:05 -07001339 // There is a minor bug here: if the attribute in the source xml
1340 // document is duplicated, it will not be detected and the
1341 // attribute will be doubly added. However, tracking the 'prevAttribute'
1342 // avoids re-scanning the attribute list. Preferring performance for
1343 // now, may reconsider in the future.
1344 if ( prevAttribute ) {
1345 prevAttribute->next = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001346 }
1347 else {
1348 rootAttribute = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001349 }
Lee Thomason97088852012-04-18 11:39:42 -07001350 prevAttribute = attrib;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351 }
Lee Thomasone4422302012-01-20 17:59:50 -08001352 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001353 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001354 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001355 return p+2; // done; sealed element.
1356 }
Lee Thomasone4422302012-01-20 17:59:50 -08001357 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001358 else if ( *p == '>' ) {
1359 ++p;
1360 break;
1361 }
Lee Thomasone4422302012-01-20 17:59:50 -08001362 else {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001363 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001364 return 0;
1365 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001366 }
Lee Thomason67d61312012-01-24 16:01:51 -08001367 return p;
1368}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001369
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001370
Lee Thomason67d61312012-01-24 16:01:51 -08001371//
1372// <ele></ele>
1373// <ele>foo<b>bar</b></ele>
1374//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001375char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001376{
1377 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001378 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001379 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001380
1381 // The closing element is the </element> form. It is
1382 // parsed just like a regular element then deleted from
1383 // the DOM.
1384 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001385 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001386 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001387 }
Lee Thomason67d61312012-01-24 16:01:51 -08001388
Lee Thomason56bdd022012-02-09 18:16:58 -08001389 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001390 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001391
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001392 p = ParseAttributes( p );
1393 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001394 return p;
1395
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001396 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001397 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001398}
1399
1400
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001401
1402XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1403{
1404 if ( !doc ) {
1405 doc = document;
1406 }
1407 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1408 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1409 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1410 }
1411 return element;
1412}
1413
1414
1415bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1416{
1417 const XMLElement* other = compare->ToElement();
1418 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1419
1420 const XMLAttribute* a=FirstAttribute();
1421 const XMLAttribute* b=other->FirstAttribute();
1422
1423 while ( a && b ) {
1424 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1425 return false;
1426 }
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001427 a = a->Next();
1428 b = b->Next();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001429 }
1430 if ( a || b ) {
1431 // different count
1432 return false;
1433 }
1434 return true;
1435 }
1436 return false;
1437}
1438
1439
Lee Thomason751da522012-02-10 08:50:51 -08001440bool XMLElement::Accept( XMLVisitor* visitor ) const
1441{
1442 if ( visitor->VisitEnter( *this, rootAttribute ) )
1443 {
1444 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1445 {
1446 if ( !node->Accept( visitor ) )
1447 break;
1448 }
1449 }
1450 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001451}
Lee Thomason56bdd022012-02-09 18:16:58 -08001452
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001453
Lee Thomason3f57d272012-01-11 15:30:03 -08001454// --------- XMLDocument ----------- //
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001455XMLDocument::XMLDocument( bool _processEntities, Whitespace _whitespace ) :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001456 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001457 writeBOM( false ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001458 processEntities( _processEntities ),
1459 errorID( 0 ),
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001460 whitespace( _whitespace ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001461 errorStr1( 0 ),
1462 errorStr2( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001463 charBuffer( 0 )
1464{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001465 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001466}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001467
1468
Lee Thomason3f57d272012-01-11 15:30:03 -08001469XMLDocument::~XMLDocument()
1470{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001471 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001472 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001473
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001474#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001475 textPool.Trace( "text" );
1476 elementPool.Trace( "element" );
1477 commentPool.Trace( "comment" );
1478 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001479#endif
1480
Lee Thomason455c9d42012-02-06 09:14:14 -08001481 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1482 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1483 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1484 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001485}
1486
1487
Lee Thomason18d68bd2012-01-26 18:17:26 -08001488void XMLDocument::InitDocument()
1489{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001490 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001491 errorStr1 = 0;
1492 errorStr2 = 0;
1493
1494 delete [] charBuffer;
1495 charBuffer = 0;
1496
1497}
1498
Lee Thomason3f57d272012-01-11 15:30:03 -08001499
Lee Thomason2c85a712012-01-31 08:24:24 -08001500XMLElement* XMLDocument::NewElement( const char* name )
1501{
Lee Thomasond1983222012-02-06 08:41:24 -08001502 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1503 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001504 ele->SetName( name );
1505 return ele;
1506}
1507
1508
Lee Thomason1ff38e02012-02-14 18:18:16 -08001509XMLComment* XMLDocument::NewComment( const char* str )
1510{
1511 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1512 comment->memPool = &commentPool;
1513 comment->SetValue( str );
1514 return comment;
1515}
1516
1517
1518XMLText* XMLDocument::NewText( const char* str )
1519{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001520 XMLText* text = new (textPool.Alloc()) XMLText( this );
1521 text->memPool = &textPool;
1522 text->SetValue( str );
1523 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001524}
1525
1526
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001527XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1528{
1529 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1530 dec->memPool = &commentPool;
Lee Thomasonf68c4382012-04-28 14:37:11 -07001531 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001532 return dec;
1533}
1534
1535
1536XMLUnknown* XMLDocument::NewUnknown( const char* str )
1537{
1538 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1539 unk->memPool = &commentPool;
1540 unk->SetValue( str );
1541 return unk;
1542}
1543
1544
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001545int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001546{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001547 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001548 InitDocument();
1549
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001550#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001551#pragma warning ( push )
1552#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001553#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001554 FILE* fp = fopen( filename, "rb" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001555#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001556#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001557#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001558 if ( !fp ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001559 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001560 return errorID;
1561 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001562 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001563 fclose( fp );
1564 return errorID;
1565}
1566
1567
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001568int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001569{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001570 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001571 InitDocument();
1572
1573 fseek( fp, 0, SEEK_END );
1574 unsigned size = ftell( fp );
1575 fseek( fp, 0, SEEK_SET );
1576
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001577 if ( size == 0 ) {
1578 return errorID;
1579 }
1580
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001581 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001582 size_t read = fread( charBuffer, 1, size, fp );
1583 if ( read != size ) {
1584 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1585 return errorID;
1586 }
1587
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001588 charBuffer[size] = 0;
1589
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001590 const char* p = charBuffer;
1591 p = XMLUtil::SkipWhiteSpace( p );
1592 p = XMLUtil::ReadBOM( p, &writeBOM );
1593 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001594 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001595 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001596 }
1597
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001598 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001599 return errorID;
1600}
1601
1602
Ken Miller81da1fb2012-04-09 23:32:26 -05001603int XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001604{
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001605#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001606#pragma warning ( push )
1607#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001608#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001609 FILE* fp = fopen( filename, "w" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001610#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001611#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001612#endif
Ken Miller81da1fb2012-04-09 23:32:26 -05001613 if ( !fp ) {
Lee Thomason7f7b1622012-03-24 12:49:03 -07001614 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001615 return errorID;
Lee Thomason7f7b1622012-03-24 12:49:03 -07001616 }
Ken Miller81da1fb2012-04-09 23:32:26 -05001617 SaveFile(fp);
1618 fclose( fp );
1619 return errorID;
1620}
1621
1622
1623int XMLDocument::SaveFile( FILE* fp )
1624{
1625 XMLPrinter stream( fp );
1626 Print( &stream );
1627 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001628}
1629
Lee Thomason1ff38e02012-02-14 18:18:16 -08001630
Lee Thomason7c913cd2012-01-26 18:32:34 -08001631int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001632{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001633 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001634 InitDocument();
1635
1636 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001637 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001638 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001639 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001640 p = XMLUtil::SkipWhiteSpace( p );
1641 p = XMLUtil::ReadBOM( p, &writeBOM );
1642 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001643 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001644 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001645 }
1646
Lee Thomason18d68bd2012-01-26 18:17:26 -08001647 size_t len = strlen( p );
1648 charBuffer = new char[ len+1 ];
1649 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001650
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001651
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001652 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001653 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001654}
1655
1656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001657void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001658{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001659 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001660 if ( !streamer )
1661 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001662 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001663}
1664
1665
Lee Thomason67d61312012-01-24 16:01:51 -08001666void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1667{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001668 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001669 errorStr1 = str1;
1670 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001671}
1672
Lee Thomason5cae8972012-01-24 18:03:07 -08001673
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001674void XMLDocument::PrintError() const
1675{
1676 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001677 static const int LEN = 20;
1678 char buf1[LEN] = { 0 };
1679 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001680
1681 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001682 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001683 }
1684 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001685 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001686 }
1687
1688 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1689 errorID, buf1, buf2 );
1690 }
1691}
1692
1693
sniperbat25900882012-05-28 17:22:07 +08001694XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001695 elementJustOpened( false ),
1696 firstElement( true ),
1697 fp( file ),
1698 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001699 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001700 processEntities( true ),
1701 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001702{
Lee Thomason857b8682012-01-25 17:50:25 -08001703 for( int i=0; i<ENTITY_RANGE; ++i ) {
1704 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001705 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001706 }
1707 for( int i=0; i<NUM_ENTITIES; ++i ) {
1708 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1709 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001710 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001711 }
1712 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001713 restrictedEntityFlag[(int)'&'] = true;
1714 restrictedEntityFlag[(int)'<'] = true;
1715 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001716 buffer.Push( 0 );
1717}
1718
1719
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001720void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001721{
1722 va_list va;
1723 va_start( va, format );
1724
1725 if ( fp ) {
1726 vfprintf( fp, format, va );
1727 }
1728 else {
1729 // This seems brutally complex. Haven't figured out a better
1730 // way on windows.
1731 #ifdef _MSC_VER
1732 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001734 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001735 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001736 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001737 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001738 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001739 }
1740 }
1741 char* p = buffer.PushArr( len ) - 1;
1742 memcpy( p, accumulator.Mem(), len+1 );
1743 #else
1744 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001745 // Close out and re-start the va-args
1746 va_end( va );
1747 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001748 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001749 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001750 #endif
1751 }
1752 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001753}
1754
1755
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001756void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001757{
1758 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001759 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001760 }
1761}
1762
1763
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001764void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001765{
Lee Thomason951d8832012-01-26 08:47:06 -08001766 // Look for runs of bytes between entities to print.
1767 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001768 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001769
Lee Thomason6f381b72012-03-02 12:59:39 -08001770 if ( processEntities ) {
1771 while ( *q ) {
1772 // Remember, char is sometimes signed. (How many times has that bitten me?)
1773 if ( *q > 0 && *q < ENTITY_RANGE ) {
1774 // Check for entities. If one is found, flush
1775 // the stream up until the entity, write the
1776 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001777 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001778 while ( p < q ) {
1779 Print( "%c", *p );
1780 ++p;
1781 }
1782 for( int i=0; i<NUM_ENTITIES; ++i ) {
1783 if ( entities[i].value == *q ) {
1784 Print( "&%s;", entities[i].pattern );
1785 break;
1786 }
1787 }
Lee Thomason951d8832012-01-26 08:47:06 -08001788 ++p;
1789 }
Lee Thomason951d8832012-01-26 08:47:06 -08001790 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001791 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001792 }
Lee Thomason951d8832012-01-26 08:47:06 -08001793 }
1794 // Flush the remaining string. This will be the entire
1795 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001796 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001797 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001798 }
Lee Thomason857b8682012-01-25 17:50:25 -08001799}
1800
U-Stream\Leeae25a442012-02-17 17:48:16 -08001801
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001802void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001803{
1804 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1805 if ( writeBOM ) {
1806 Print( "%s", bom );
1807 }
1808 if ( writeDec ) {
1809 PushDeclaration( "xml version=\"1.0\"" );
1810 }
1811}
1812
1813
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001814void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001815{
1816 if ( elementJustOpened ) {
1817 SealElement();
1818 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001819 stack.Push( name );
1820
sniperbat25900882012-05-28 17:22:07 +08001821 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001822 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001823 PrintSpace( depth );
1824 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001825
U-Stream\Leeae25a442012-02-17 17:48:16 -08001826 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001827 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001828 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001829 ++depth;
1830}
1831
1832
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001833void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001834{
1835 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001836 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001838 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001839}
1840
1841
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001842void XMLPrinter::PushAttribute( const char* name, int v )
1843{
1844 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001845 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001846 PushAttribute( name, buf );
1847}
1848
1849
1850void XMLPrinter::PushAttribute( const char* name, unsigned v )
1851{
1852 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001853 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001854 PushAttribute( name, buf );
1855}
1856
1857
1858void XMLPrinter::PushAttribute( const char* name, bool v )
1859{
1860 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001861 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001862 PushAttribute( name, buf );
1863}
1864
1865
1866void XMLPrinter::PushAttribute( const char* name, double v )
1867{
1868 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001869 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001870 PushAttribute( name, buf );
1871}
1872
1873
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001874void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001875{
1876 --depth;
1877 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001878
1879 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001880 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001881 }
1882 else {
sniperbat25900882012-05-28 17:22:07 +08001883 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001884 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001885 PrintSpace( depth );
1886 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001887 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001888 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001889
1890 if ( textDepth == depth )
1891 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001892 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001893 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001894 elementJustOpened = false;
1895}
1896
1897
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001898void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001899{
1900 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001901 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001902}
1903
1904
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001905void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001906{
Lee Thomason56bdd022012-02-09 18:16:58 -08001907 textDepth = depth-1;
1908
Lee Thomason5cae8972012-01-24 18:03:07 -08001909 if ( elementJustOpened ) {
1910 SealElement();
1911 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001913 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001914 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001915 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001916 }
1917 else {
1918 PrintString( text, true );
1919 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001920}
1921
Lee Thomason21be8822012-07-15 17:27:22 -07001922void XMLPrinter::PushText( int value )
1923{
1924 char buf[BUF_SIZE];
1925 XMLUtil::ToStr( value, buf, BUF_SIZE );
1926 PushText( buf, false );
1927}
1928
1929
1930void XMLPrinter::PushText( unsigned value )
1931{
1932 char buf[BUF_SIZE];
1933 XMLUtil::ToStr( value, buf, BUF_SIZE );
1934 PushText( buf, false );
1935}
1936
1937
1938void XMLPrinter::PushText( bool value )
1939{
1940 char buf[BUF_SIZE];
1941 XMLUtil::ToStr( value, buf, BUF_SIZE );
1942 PushText( buf, false );
1943}
1944
1945
1946void XMLPrinter::PushText( float value )
1947{
1948 char buf[BUF_SIZE];
1949 XMLUtil::ToStr( value, buf, BUF_SIZE );
1950 PushText( buf, false );
1951}
1952
1953
1954void XMLPrinter::PushText( double value )
1955{
1956 char buf[BUF_SIZE];
1957 XMLUtil::ToStr( value, buf, BUF_SIZE );
1958 PushText( buf, false );
1959}
1960
Lee Thomason5cae8972012-01-24 18:03:07 -08001961
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001962void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001963{
1964 if ( elementJustOpened ) {
1965 SealElement();
1966 }
sniperbat25900882012-05-28 17:22:07 +08001967 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001968 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001969 PrintSpace( depth );
1970 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001971 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001972 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001973}
Lee Thomason751da522012-02-10 08:50:51 -08001974
1975
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001976void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977{
1978 if ( elementJustOpened ) {
1979 SealElement();
1980 }
sniperbat25900882012-05-28 17:22:07 +08001981 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001982 Print( "\n" );
1983 PrintSpace( depth );
1984 }
1985 firstElement = false;
1986 Print( "<?%s?>", value );
1987}
1988
1989
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001990void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001991{
1992 if ( elementJustOpened ) {
1993 SealElement();
1994 }
sniperbat25900882012-05-28 17:22:07 +08001995 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001996 Print( "\n" );
1997 PrintSpace( depth );
1998 }
1999 firstElement = false;
2000 Print( "<!%s>", value );
2001}
2002
2003
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002004bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002005{
Lee Thomason6f381b72012-03-02 12:59:39 -08002006 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002007 if ( doc.HasBOM() ) {
2008 PushHeader( true, false );
2009 }
2010 return true;
2011}
2012
2013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002015{
2016 OpenElement( element.Name() );
2017 while ( attribute ) {
2018 PushAttribute( attribute->Name(), attribute->Value() );
2019 attribute = attribute->Next();
2020 }
2021 return true;
2022}
2023
2024
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002025bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002026{
2027 CloseElement();
2028 return true;
2029}
2030
2031
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002032bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002033{
Lee Thomasond6277762012-02-22 16:00:12 -08002034 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08002035 return true;
2036}
2037
2038
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002039bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002040{
2041 PushComment( comment.Value() );
2042 return true;
2043}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002044
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002045bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002046{
2047 PushDeclaration( declaration.Value() );
2048 return true;
2049}
2050
2051
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002052bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002053{
2054 PushUnknown( unknown.Value() );
2055 return true;
2056}