blob: 73a41435f9be92de2ba09990bc4f6b866cfafe40 [file] [log] [blame]
U-Lama\Lee560bd472011-12-28 19:42:49 -08001#include "tinyxml2.h"
2
3#include <string.h>
4#include <stdlib.h>
5#include <stdio.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -08006#include <ctype.h>
Lee Thomasond1983222012-02-06 08:41:24 -08007#include <new.h>
U-Stream\Leeae25a442012-02-17 17:48:16 -08008#include <stdarg.h>
Lee Thomasond1983222012-02-06 08:41:24 -08009
10//#pragma warning ( disable : 4291 )
U-Lama\Lee560bd472011-12-28 19:42:49 -080011
12using namespace tinyxml2;
13
Lee Thomasone4422302012-01-20 17:59:50 -080014static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080015static const char LF = LINE_FEED;
16static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
17static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080018static const char SINGLE_QUOTE = '\'';
19static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080020
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080021// Bunch of unicode info at:
22// http://www.unicode.org/faq/utf_bom.html
23// ef bb bf (Microsoft "lead bytes") - designates UTF-8
24
25static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
26static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
27static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080028
29
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080030#define DELETE_NODE( node ) { \
31 if ( node ) { \
32 MemPool* pool = node->memPool; \
33 node->~XMLNode(); \
34 pool->Free( node ); \
35 } \
36}
37#define DELETE_ATTRIBUTE( attrib ) { \
38 if ( attrib ) { \
39 MemPool* pool = attrib->memPool; \
40 attrib->~XMLAttribute(); \
41 pool->Free( attrib ); \
42 } \
43}
Lee Thomason43f59302012-02-06 18:18:11 -080044
Lee Thomason8ee79892012-01-25 17:44:30 -080045struct Entity {
46 const char* pattern;
47 int length;
48 char value;
49};
50
51static const int NUM_ENTITIES = 5;
52static const Entity entities[NUM_ENTITIES] =
53{
Lee Thomason18d68bd2012-01-26 18:17:26 -080054 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080055 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080056 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080057 { "lt", 2, '<' },
58 { "gt", 2, '>' }
59};
60
Lee Thomasonfde6a752012-01-14 18:08:12 -080061
Lee Thomason1a1d4a72012-02-15 09:09:25 -080062StrPair::~StrPair()
63{
64 Reset();
65}
66
67
68void StrPair::Reset()
69{
70 if ( flags & NEEDS_DELETE ) {
71 delete [] start;
72 }
73 flags = 0;
74 start = 0;
75 end = 0;
76}
77
78
79void StrPair::SetStr( const char* str, int flags )
80{
81 Reset();
82 size_t len = strlen( str );
83 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -080084 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085 end = start + len;
86 this->flags = flags | NEEDS_DELETE;
87}
88
89
90char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
91{
92 TIXMLASSERT( endTag && *endTag );
93
94 char* start = p; // fixme: hides a member
95 char endChar = *endTag;
96 int length = strlen( endTag );
97
98 // Inner loop of text parsing.
99 while ( *p ) {
100 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
101 Set( start, p, strFlags );
102 return p + length;
103 }
104 ++p;
105 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800106 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800107}
108
109
110char* StrPair::ParseName( char* p )
111{
112 char* start = p;
113
114 start = p;
115 if ( !start || !(*start) ) {
116 return 0;
117 }
118
119 if ( !XMLUtil::IsAlpha( *p ) ) {
120 return 0;
121 }
122
123 while( *p && (
124 XMLUtil::IsAlphaNum( (unsigned char) *p )
125 || *p == '_'
126 || *p == '-'
127 || *p == '.'
128 || *p == ':' ))
129 {
130 ++p;
131 }
132
133 if ( p > start ) {
134 Set( start, p, 0 );
135 return p;
136 }
137 return 0;
138}
139
140
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800141
Lee Thomasone4422302012-01-20 17:59:50 -0800142const char* StrPair::GetStr()
143{
144 if ( flags & NEEDS_FLUSH ) {
145 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800146 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800147
Lee Thomason8ee79892012-01-25 17:44:30 -0800148 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800149 char* p = start; // the read pointer
150 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800151
152 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800153 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800154 // CR-LF pair becomes LF
155 // CR alone becomes LF
156 // LF-CR becomes LF
157 if ( *(p+1) == LF ) {
158 p += 2;
159 }
160 else {
161 ++p;
162 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800163 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800164 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800165 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800166 if ( *(p+1) == CR ) {
167 p += 2;
168 }
169 else {
170 ++p;
171 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800172 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800173 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800174 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
175 int i=0;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800176
177 // Entities handled by tinyXML2:
178 // - special entities in the entity table [in/out]
179 // - numeric character reference [in]
180 // &#20013; or &#x4e2d;
181
182 if ( *(p+1) == '#' ) {
183 char buf[10] = { 0 };
184 int len;
185 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
186 for( int i=0; i<len; ++i ) {
187 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800188 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800189 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800190 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800191 else {
192 for( i=0; i<NUM_ENTITIES; ++i ) {
193 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
194 && *(p+entities[i].length+1) == ';' )
195 {
196 // Found an entity convert;
197 *q = entities[i].value;
198 ++q;
199 p += entities[i].length + 2;
200 break;
201 }
202 }
203 if ( i == NUM_ENTITIES ) {
204 // fixme: treat as error?
205 ++p;
206 ++q;
207 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800208 }
209 }
Lee Thomasone4422302012-01-20 17:59:50 -0800210 else {
211 *q = *p;
212 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800213 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800214 }
215 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800216 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800217 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800218 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800219 }
220 return start;
221}
222
Lee Thomason2c85a712012-01-31 08:24:24 -0800223
Lee Thomasone4422302012-01-20 17:59:50 -0800224
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800225
Lee Thomason56bdd022012-02-09 18:16:58 -0800226// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800227
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800228const char* XMLUtil::ReadBOM( const char* p, bool* bom )
229{
230 *bom = false;
231 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
232 // Check for BOM:
233 if ( *(pu+0) == TIXML_UTF_LEAD_0
234 && *(pu+1) == TIXML_UTF_LEAD_1
235 && *(pu+2) == TIXML_UTF_LEAD_2 )
236 {
237 *bom = true;
238 p += 3;
239 }
240 return p;
241}
242
243
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800244void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
245{
246 const unsigned long BYTE_MASK = 0xBF;
247 const unsigned long BYTE_MARK = 0x80;
248 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
249
250 if (input < 0x80)
251 *length = 1;
252 else if ( input < 0x800 )
253 *length = 2;
254 else if ( input < 0x10000 )
255 *length = 3;
256 else if ( input < 0x200000 )
257 *length = 4;
258 else
259 { *length = 0; return; } // This code won't covert this correctly anyway.
260
261 output += *length;
262
263 // Scary scary fall throughs.
264 switch (*length)
265 {
266 case 4:
267 --output;
268 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
269 input >>= 6;
270 case 3:
271 --output;
272 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
273 input >>= 6;
274 case 2:
275 --output;
276 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
277 input >>= 6;
278 case 1:
279 --output;
280 *output = (char)(input | FIRST_BYTE_MARK[*length]);
281 }
282}
283
284
285const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
286{
287 // Presume an entity, and pull it out.
288 *length = 0;
289
290 if ( *(p+1) == '#' && *(p+2) )
291 {
292 unsigned long ucs = 0;
293 ptrdiff_t delta = 0;
294 unsigned mult = 1;
295
296 if ( *(p+2) == 'x' )
297 {
298 // Hexadecimal.
299 if ( !*(p+3) ) return 0;
300
301 const char* q = p+3;
302 q = strchr( q, ';' );
303
304 if ( !q || !*q ) return 0;
305
306 delta = q-p;
307 --q;
308
309 while ( *q != 'x' )
310 {
311 if ( *q >= '0' && *q <= '9' )
312 ucs += mult * (*q - '0');
313 else if ( *q >= 'a' && *q <= 'f' )
314 ucs += mult * (*q - 'a' + 10);
315 else if ( *q >= 'A' && *q <= 'F' )
316 ucs += mult * (*q - 'A' + 10 );
317 else
318 return 0;
319 mult *= 16;
320 --q;
321 }
322 }
323 else
324 {
325 // Decimal.
326 if ( !*(p+2) ) return 0;
327
328 const char* q = p+2;
329 q = strchr( q, ';' );
330
331 if ( !q || !*q ) return 0;
332
333 delta = q-p;
334 --q;
335
336 while ( *q != '#' )
337 {
338 if ( *q >= '0' && *q <= '9' )
339 ucs += mult * (*q - '0');
340 else
341 return 0;
342 mult *= 10;
343 --q;
344 }
345 }
346 // convert the UCS to UTF-8
347 ConvertUTF32ToUTF8( ucs, value, length );
348 return p + delta + 1;
349 }
350 return p+1;
351}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800352
353
Lee Thomasond1983222012-02-06 08:41:24 -0800354char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800355{
356 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800357 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800358 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800359 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800360 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800361 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800362 }
363
364 // What is this thing?
365 // - Elements start with a letter or underscore, but xml is reserved.
366 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800367 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800368 // - Everthing else is unknown to tinyxml.
369 //
370
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800371 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800372 static const char* commentHeader = { "<!--" };
373 static const char* dtdHeader = { "<!" };
374 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800375 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800376
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800377 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800378 static const int commentHeaderLen = 4;
379 static const int dtdHeaderLen = 2;
380 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800381 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800382
Lee Thomason50f97b22012-02-11 16:33:40 -0800383 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
384 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
385
386 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
387 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
388 returnNode->memPool = &commentPool;
389 p += xmlHeaderLen;
390 }
391 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800392 returnNode = new (commentPool.Alloc()) XMLComment( this );
393 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800394 p += commentHeaderLen;
395 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800396 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
397 XMLText* text = new (textPool.Alloc()) XMLText( this );
398 returnNode = text;
399 returnNode->memPool = &textPool;
400 p += cdataHeaderLen;
401 text->SetCData( true );
402 }
403 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
404 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
405 returnNode->memPool = &commentPool;
406 p += dtdHeaderLen;
407 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800408 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800409 returnNode = new (elementPool.Alloc()) XMLElement( this );
410 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800411 p += elementHeaderLen;
412 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800413 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800414 returnNode = new (textPool.Alloc()) XMLText( this );
415 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800416 p = start; // Back it up, all the text counts.
417 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800418
419 *node = returnNode;
420 return p;
421}
422
423
Lee Thomason751da522012-02-10 08:50:51 -0800424bool XMLDocument::Accept( XMLVisitor* visitor ) const
425{
426 if ( visitor->VisitEnter( *this ) )
427 {
428 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
429 {
430 if ( !node->Accept( visitor ) )
431 break;
432 }
433 }
434 return visitor->VisitExit( *this );
435}
Lee Thomason56bdd022012-02-09 18:16:58 -0800436
437
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800438// --------- XMLNode ----------- //
439
440XMLNode::XMLNode( XMLDocument* doc ) :
441 document( doc ),
442 parent( 0 ),
443 firstChild( 0 ), lastChild( 0 ),
444 prev( 0 ), next( 0 )
445{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800446}
447
448
449XMLNode::~XMLNode()
450{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800451 ClearChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800452 if ( parent ) {
453 parent->Unlink( this );
454 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800455}
456
457
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800458void XMLNode::SetValue( const char* str, bool staticMem )
459{
460 if ( staticMem )
461 value.SetInternedStr( str );
462 else
463 value.SetStr( str );
464}
465
466
Lee Thomason18d68bd2012-01-26 18:17:26 -0800467void XMLNode::ClearChildren()
468{
Lee Thomasond923c672012-01-23 08:44:25 -0800469 while( firstChild ) {
470 XMLNode* node = firstChild;
471 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800472
Lee Thomason43f59302012-02-06 18:18:11 -0800473 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800474 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800475 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800476}
477
478
479void XMLNode::Unlink( XMLNode* child )
480{
481 TIXMLASSERT( child->parent == this );
482 if ( child == firstChild )
483 firstChild = firstChild->next;
484 if ( child == lastChild )
485 lastChild = lastChild->prev;
486
487 if ( child->prev ) {
488 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800489 }
Lee Thomasond923c672012-01-23 08:44:25 -0800490 if ( child->next ) {
491 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800492 }
Lee Thomasond923c672012-01-23 08:44:25 -0800493 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494}
495
496
U-Stream\Leeae25a442012-02-17 17:48:16 -0800497void XMLNode::DeleteChild( XMLNode* node )
498{
499 TIXMLASSERT( node->parent == this );
500 DELETE_NODE( node );
501}
502
503
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800504XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
505{
506 if ( lastChild ) {
507 TIXMLASSERT( firstChild );
508 TIXMLASSERT( lastChild->next == 0 );
509 lastChild->next = addThis;
510 addThis->prev = lastChild;
511 lastChild = addThis;
512
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800513 addThis->next = 0;
514 }
515 else {
516 TIXMLASSERT( firstChild == 0 );
517 firstChild = lastChild = addThis;
518
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519 addThis->prev = 0;
520 addThis->next = 0;
521 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800522 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800523 return addThis;
524}
525
526
Lee Thomason1ff38e02012-02-14 18:18:16 -0800527XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
528{
529 if ( firstChild ) {
530 TIXMLASSERT( lastChild );
531 TIXMLASSERT( firstChild->prev == 0 );
532
533 firstChild->prev = addThis;
534 addThis->next = firstChild;
535 firstChild = addThis;
536
Lee Thomason1ff38e02012-02-14 18:18:16 -0800537 addThis->prev = 0;
538 }
539 else {
540 TIXMLASSERT( lastChild == 0 );
541 firstChild = lastChild = addThis;
542
Lee Thomason1ff38e02012-02-14 18:18:16 -0800543 addThis->prev = 0;
544 addThis->next = 0;
545 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800546 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800547 return addThis;
548}
549
550
551XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
552{
553 TIXMLASSERT( afterThis->parent == this );
554 if ( afterThis->parent != this )
555 return 0;
556
557 if ( afterThis->next == 0 ) {
558 // The last node or the only node.
559 return InsertEndChild( addThis );
560 }
561 addThis->prev = afterThis;
562 addThis->next = afterThis->next;
563 afterThis->next->prev = addThis;
564 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800565 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800566 return addThis;
567}
568
569
570
571
Lee Thomason56bdd022012-02-09 18:16:58 -0800572const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800573{
574 for( XMLNode* node=firstChild; node; node=node->next ) {
575 XMLElement* element = node->ToElement();
576 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800577 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800578 return element;
579 }
580 }
581 }
582 return 0;
583}
584
585
Lee Thomason56bdd022012-02-09 18:16:58 -0800586const XMLElement* XMLNode::LastChildElement( const char* value ) const
587{
588 for( XMLNode* node=lastChild; node; node=node->prev ) {
589 XMLElement* element = node->ToElement();
590 if ( element ) {
591 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
592 return element;
593 }
594 }
595 }
596 return 0;
597}
598
599
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800600char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800601{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800602 // This is a recursive method, but thinking about it "at the current level"
603 // it is a pretty simple flat list:
604 // <foo/>
605 // <!-- comment -->
606 //
607 // With a special case:
608 // <foo>
609 // </foo>
610 // <!-- comment -->
611 //
612 // Where the closing element (/foo) *must* be the next thing after the opening
613 // element, and the names must match. BUT the tricky bit is that the closing
614 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800615 //
616 // 'endTag' is the end tag for this node, it is returned by a call to a child.
617 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800618
Lee Thomason67d61312012-01-24 16:01:51 -0800619 while( p && *p ) {
620 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800621
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800622 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800623 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800624 break;
625 }
626
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800627 StrPair endTag;
628 p = node->ParseDeep( p, &endTag );
629 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800630 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800631 node = 0;
632 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800633 }
634
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800635 // We read the end tag. Return it to the parent.
636 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
637 if ( parentEnd ) {
638 *parentEnd = ((XMLElement*)node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800639 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800640 DELETE_NODE( node );
641 return p;
642 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800643
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800644 // Handle an end tag returned to this level.
645 // And handle a bunch of annoying errors.
646 XMLElement* ele = node->ToElement();
647 if ( ele ) {
648 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
649 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
650 p = 0;
651 }
652 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
653 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
654 p = 0;
655 }
656 else if ( !endTag.Empty() ) {
657 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800658 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
659 p = 0;
660 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800661 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800662 }
663 if ( p == 0 ) {
664 DELETE_NODE( node );
665 node = 0;
666 }
667 if ( node ) {
668 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800669 }
670 }
671 return 0;
672}
673
Lee Thomason5492a1c2012-01-23 15:32:10 -0800674// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800675char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800676{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800677 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800678 if ( this->CData() ) {
679 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800680 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800681 document->SetError( ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800682 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800683 return p;
684 }
685 else {
686 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800687 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800688 document->SetError( ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800689 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800690 if ( p && *p ) {
691 return p-1;
692 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800693 }
694 return 0;
695}
696
697
Lee Thomason56bdd022012-02-09 18:16:58 -0800698bool XMLText::Accept( XMLVisitor* visitor ) const
699{
700 return visitor->Visit( *this );
701}
702
703
Lee Thomason3f57d272012-01-11 15:30:03 -0800704// --------- XMLComment ---------- //
705
Lee Thomasone4422302012-01-20 17:59:50 -0800706XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800707{
708}
709
710
Lee Thomasonce0763e2012-01-11 15:43:54 -0800711XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800712{
Lee Thomasond923c672012-01-23 08:44:25 -0800713 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800714}
715
716
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800717char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800718{
719 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800720 const char* start = p;
721 p = value.ParseText( p, "-->", StrPair::COMMENT );
722 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800723 document->SetError( ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800724 }
725 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800726}
727
728
Lee Thomason751da522012-02-10 08:50:51 -0800729bool XMLComment::Accept( XMLVisitor* visitor ) const
730{
731 return visitor->Visit( *this );
732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason50f97b22012-02-11 16:33:40 -0800735// --------- XMLDeclaration ---------- //
736
737XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
738{
739}
740
741
742XMLDeclaration::~XMLDeclaration()
743{
744 //printf( "~XMLDeclaration\n" );
745}
746
747
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800748char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800749{
750 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800751 const char* start = p;
752 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
753 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800754 document->SetError( ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800755 }
756 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800757}
758
759
760bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
761{
762 return visitor->Visit( *this );
763}
764
765// --------- XMLUnknown ---------- //
766
767XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
768{
769}
770
771
772XMLUnknown::~XMLUnknown()
773{
774}
775
776
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800777char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800778{
779 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800780 const char* start = p;
781
782 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
783 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800784 document->SetError( ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800785 }
786 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800787}
788
789
790bool XMLUnknown::Accept( XMLVisitor* visitor ) const
791{
792 return visitor->Visit( *this );
793}
794
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800795// --------- XMLAttribute ---------- //
796char* XMLAttribute::ParseDeep( char* p )
797{
Lee Thomason56bdd022012-02-09 18:16:58 -0800798 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800799 if ( !p || !*p ) return 0;
800
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801 char endTag[2] = { *p, 0 };
802 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800803 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800804 //if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805 return p;
806}
807
808
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800809void XMLAttribute::SetName( const char* n )
810{
811 name.SetStr( n );
812}
813
814
Lee Thomason1ff38e02012-02-14 18:18:16 -0800815int XMLAttribute::QueryIntAttribute( int* value ) const
816{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800817 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800818 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800819 return WRONG_ATTRIBUTE_TYPE;
820}
821
822
823int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
824{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800825 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800826 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800827 return WRONG_ATTRIBUTE_TYPE;
828}
829
830
831int XMLAttribute::QueryBoolAttribute( bool* value ) const
832{
833 int ival = -1;
834 QueryIntAttribute( &ival );
835
836 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
837 *value = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800838 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800839 }
840 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
841 *value = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800842 return XML_NO_ERROR;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800843 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800844 return WRONG_ATTRIBUTE_TYPE;
845}
846
847
848int XMLAttribute::QueryDoubleAttribute( double* value ) const
849{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800850 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800851 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800852 return WRONG_ATTRIBUTE_TYPE;
853}
854
855
856int XMLAttribute::QueryFloatAttribute( float* value ) const
857{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800858 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800859 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800860 return WRONG_ATTRIBUTE_TYPE;
861}
862
863
864void XMLAttribute::SetAttribute( const char* v )
865{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800866 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800867}
868
869
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870void XMLAttribute::SetAttribute( int v )
871{
872 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800873 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
874 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800875}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800876
877
878void XMLAttribute::SetAttribute( unsigned v )
879{
880 char buf[BUF_SIZE];
881 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
882 value.SetStr( buf );
883}
884
885
886void XMLAttribute::SetAttribute( bool v )
887{
888 char buf[BUF_SIZE];
889 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
890 value.SetStr( buf );
891}
892
893void XMLAttribute::SetAttribute( double v )
894{
895 char buf[BUF_SIZE];
896 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
897 value.SetStr( buf );
898}
899
900void XMLAttribute::SetAttribute( float v )
901{
902 char buf[BUF_SIZE];
903 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
904 value.SetStr( buf );
905}
906
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800907
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800908// --------- XMLElement ---------- //
909XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800910 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800911 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800912{
913}
914
915
916XMLElement::~XMLElement()
917{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800918 while( rootAttribute ) {
919 XMLAttribute* next = rootAttribute->next;
920 DELETE_ATTRIBUTE( rootAttribute );
921 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800922 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800923}
924
925
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800926XMLAttribute* XMLElement::FindAttribute( const char* name )
927{
928 XMLAttribute* a = 0;
929 for( a=rootAttribute; a; a = a->next ) {
930 if ( XMLUtil::StringEqual( a->Name(), name ) )
931 return a;
932 }
933 return 0;
934}
935
936
937const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
938{
939 XMLAttribute* a = 0;
940 for( a=rootAttribute; a; a = a->next ) {
941 if ( XMLUtil::StringEqual( a->Name(), name ) )
942 return a;
943 }
944 return 0;
945}
946
947
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800948const char* XMLElement::GetText() const
949{
950 if ( FirstChild() && FirstChild()->ToText() ) {
951 return FirstChild()->ToText()->Value();
952 }
953 return 0;
954}
955
956
957
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800958XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
959{
960 XMLAttribute* attrib = FindAttribute( name );
961 if ( !attrib ) {
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800962 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800963 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800964 LinkAttribute( attrib );
965 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800966 }
967 return attrib;
968}
969
970
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800971void XMLElement::LinkAttribute( XMLAttribute* attrib )
972{
973 if ( rootAttribute ) {
974 XMLAttribute* end = rootAttribute;
975 while ( end->next )
976 end = end->next;
977 end->next = attrib;
978 }
979 else {
980 rootAttribute = attrib;
981 }
982}
983
984
U-Stream\Leeae25a442012-02-17 17:48:16 -0800985void XMLElement::DeleteAttribute( const char* name )
986{
987 XMLAttribute* prev = 0;
988 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
989 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
990 if ( prev ) {
991 prev->next = a->next;
992 }
993 else {
994 rootAttribute = a->next;
995 }
996 DELETE_ATTRIBUTE( a );
997 break;
998 }
999 prev = a;
1000 }
1001}
1002
1003
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001004char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001005{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001006 const char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001007
1008 // Read the attributes.
1009 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001010 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001011 if ( !p || !(*p) ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001012 document->SetError( ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001013 return 0;
1014 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001015
1016 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001017 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001018 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
1019 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001020
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001021 p = attrib->ParseDeep( p );
Lee Thomasond6277762012-02-22 16:00:12 -08001022 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001023 DELETE_ATTRIBUTE( attrib );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001024 document->SetError( ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001025 return 0;
1026 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001027 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001028 }
Lee Thomasone4422302012-01-20 17:59:50 -08001029 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001030 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001031 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001032 return p+2; // done; sealed element.
1033 }
Lee Thomasone4422302012-01-20 17:59:50 -08001034 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001035 else if ( *p == '>' ) {
1036 ++p;
1037 break;
1038 }
Lee Thomasone4422302012-01-20 17:59:50 -08001039 else {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001040 document->SetError( ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001041 return 0;
1042 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001043 }
Lee Thomason67d61312012-01-24 16:01:51 -08001044 return p;
1045}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001046
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001047
Lee Thomason67d61312012-01-24 16:01:51 -08001048//
1049// <ele></ele>
1050// <ele>foo<b>bar</b></ele>
1051//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001052char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001053{
1054 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001055 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001056 if ( !p ) return 0;
1057 const char* start = p;
1058
1059 // The closing element is the </element> form. It is
1060 // parsed just like a regular element then deleted from
1061 // the DOM.
1062 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001063 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001064 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001065 }
Lee Thomason67d61312012-01-24 16:01:51 -08001066
Lee Thomason56bdd022012-02-09 18:16:58 -08001067 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001068 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001069
1070 bool elementClosed=false;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001071 p = ParseAttributes( p );
1072 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001073 return p;
1074
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001075 p = XMLNode::ParseDeep( p, strPair );
1076 // FIXME: proces end tage here??
Lee Thomason67d61312012-01-24 16:01:51 -08001077 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078}
1079
1080
Lee Thomason751da522012-02-10 08:50:51 -08001081bool XMLElement::Accept( XMLVisitor* visitor ) const
1082{
1083 if ( visitor->VisitEnter( *this, rootAttribute ) )
1084 {
1085 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1086 {
1087 if ( !node->Accept( visitor ) )
1088 break;
1089 }
1090 }
1091 return visitor->VisitExit( *this );
1092
1093}
Lee Thomason56bdd022012-02-09 18:16:58 -08001094
Lee Thomason3f57d272012-01-11 15:30:03 -08001095// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -08001096XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001097 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001098 writeBOM( false ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001099 charBuffer( 0 )
1100{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001101 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001102}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001103
1104
Lee Thomason3f57d272012-01-11 15:30:03 -08001105XMLDocument::~XMLDocument()
1106{
Lee Thomasond1983222012-02-06 08:41:24 -08001107 ClearChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001108 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001109
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001110#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001111 textPool.Trace( "text" );
1112 elementPool.Trace( "element" );
1113 commentPool.Trace( "comment" );
1114 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001115#endif
1116
Lee Thomason455c9d42012-02-06 09:14:14 -08001117 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1118 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1119 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1120 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001121}
1122
1123
Lee Thomason18d68bd2012-01-26 18:17:26 -08001124void XMLDocument::InitDocument()
1125{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001126 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001127 errorStr1 = 0;
1128 errorStr2 = 0;
1129
1130 delete [] charBuffer;
1131 charBuffer = 0;
1132
1133}
1134
Lee Thomason3f57d272012-01-11 15:30:03 -08001135
Lee Thomason2c85a712012-01-31 08:24:24 -08001136XMLElement* XMLDocument::NewElement( const char* name )
1137{
Lee Thomasond1983222012-02-06 08:41:24 -08001138 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1139 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001140 ele->SetName( name );
1141 return ele;
1142}
1143
1144
Lee Thomason1ff38e02012-02-14 18:18:16 -08001145XMLComment* XMLDocument::NewComment( const char* str )
1146{
1147 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1148 comment->memPool = &commentPool;
1149 comment->SetValue( str );
1150 return comment;
1151}
1152
1153
1154XMLText* XMLDocument::NewText( const char* str )
1155{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001156 XMLText* text = new (textPool.Alloc()) XMLText( this );
1157 text->memPool = &textPool;
1158 text->SetValue( str );
1159 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001163int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001164{
1165 ClearChildren();
1166 InitDocument();
1167
1168 FILE* fp = fopen( filename, "rb" );
1169 if ( !fp ) {
1170 SetError( ERROR_FILE_NOT_FOUND, filename, 0 );
1171 return errorID;
1172 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001173 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001174 fclose( fp );
1175 return errorID;
1176}
1177
1178
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001179int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001180{
1181 ClearChildren();
1182 InitDocument();
1183
1184 fseek( fp, 0, SEEK_END );
1185 unsigned size = ftell( fp );
1186 fseek( fp, 0, SEEK_SET );
1187
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001188 if ( size == 0 ) {
1189 return errorID;
1190 }
1191
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001192 charBuffer = new char[size+1];
1193 fread( charBuffer, size, 1, fp );
1194 charBuffer[size] = 0;
1195
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001196 const char* p = charBuffer;
1197 p = XMLUtil::SkipWhiteSpace( p );
1198 p = XMLUtil::ReadBOM( p, &writeBOM );
1199 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001200 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1201 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001202 }
1203
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001204 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001205 return errorID;
1206}
1207
1208
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001209void XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001210{
1211 FILE* fp = fopen( filename, "w" );
1212 XMLStreamer stream( fp );
1213 Print( &stream );
1214 fclose( fp );
1215}
1216
Lee Thomason1ff38e02012-02-14 18:18:16 -08001217
Lee Thomason7c913cd2012-01-26 18:32:34 -08001218int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001219{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001220 ClearChildren();
1221 InitDocument();
1222
1223 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001224 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1225 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001226 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001227 p = XMLUtil::SkipWhiteSpace( p );
1228 p = XMLUtil::ReadBOM( p, &writeBOM );
1229 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001230 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1231 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001232 }
1233
Lee Thomason18d68bd2012-01-26 18:17:26 -08001234 size_t len = strlen( p );
1235 charBuffer = new char[ len+1 ];
1236 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001237
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001238
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001239 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001240 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001241}
1242
1243
Lee Thomason5cae8972012-01-24 18:03:07 -08001244void XMLDocument::Print( XMLStreamer* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001245{
Lee Thomason5cae8972012-01-24 18:03:07 -08001246 XMLStreamer stdStreamer( stdout );
1247 if ( !streamer )
1248 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001249 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001250}
1251
1252
Lee Thomason67d61312012-01-24 16:01:51 -08001253void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1254{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001255 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001256 errorStr1 = str1;
1257 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001258}
1259
Lee Thomason5cae8972012-01-24 18:03:07 -08001260
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001261void XMLDocument::PrintError() const
1262{
1263 if ( errorID ) {
1264 char buf1[20] = { 0 };
1265 char buf2[20] = { 0 };
1266
1267 if ( errorStr1 ) {
1268 strncpy( buf1, errorStr1, 20 );
1269 buf1[19] = 0;
1270 }
1271 if ( errorStr2 ) {
1272 strncpy( buf2, errorStr2, 20 );
1273 buf2[19] = 0;
1274 }
1275
1276 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1277 errorID, buf1, buf2 );
1278 }
1279}
1280
1281
1282XMLStreamer::XMLStreamer( FILE* file ) :
1283 elementJustOpened( false ),
1284 firstElement( true ),
1285 fp( file ),
1286 depth( 0 ),
1287 textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -08001288{
Lee Thomason857b8682012-01-25 17:50:25 -08001289 for( int i=0; i<ENTITY_RANGE; ++i ) {
1290 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001291 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001292 }
1293 for( int i=0; i<NUM_ENTITIES; ++i ) {
1294 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1295 if ( entities[i].value < ENTITY_RANGE ) {
1296 entityFlag[ entities[i].value ] = true;
1297 }
1298 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001299 restrictedEntityFlag['&'] = true;
1300 restrictedEntityFlag['<'] = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001301 restrictedEntityFlag['>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001302 buffer.Push( 0 );
1303}
1304
1305
1306void XMLStreamer::Print( const char* format, ... )
1307{
1308 va_list va;
1309 va_start( va, format );
1310
1311 if ( fp ) {
1312 vfprintf( fp, format, va );
1313 }
1314 else {
1315 // This seems brutally complex. Haven't figured out a better
1316 // way on windows.
1317 #ifdef _MSC_VER
1318 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001319 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001320 while ( len < 0 ) {
1321 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
1322 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001323 accumulator.PushArr( expand );
1324 expand *= 3/2;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001325 }
1326 }
1327 char* p = buffer.PushArr( len ) - 1;
1328 memcpy( p, accumulator.Mem(), len+1 );
1329 #else
1330 int len = vsnprintf( 0, 0, format, va );
1331 char* p = buffer.PushArr( len ) - 1;
1332 vsprintf_s( p, len+1, format, va );
1333 #endif
1334 }
1335 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001336}
1337
1338
1339void XMLStreamer::PrintSpace( int depth )
1340{
1341 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001342 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001343 }
1344}
1345
1346
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001347void XMLStreamer::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001348{
Lee Thomason951d8832012-01-26 08:47:06 -08001349 // Look for runs of bytes between entities to print.
1350 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001351 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001352
Lee Thomason951d8832012-01-26 08:47:06 -08001353 while ( *q ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001354 // Remember, char is sometimes signed. (How many times has that bitten me?)
1355 if ( *q > 0 && *q < ENTITY_RANGE ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001356 // Check for entities. If one is found, flush
1357 // the stream up until the entity, write the
1358 // entity, and keep looking.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001359 if ( flag[*q] ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001360 while ( p < q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001361 Print( "%c", *p );
Lee Thomason951d8832012-01-26 08:47:06 -08001362 ++p;
1363 }
1364 for( int i=0; i<NUM_ENTITIES; ++i ) {
1365 if ( entities[i].value == *q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001366 Print( "&%s;", entities[i].pattern );
Lee Thomason951d8832012-01-26 08:47:06 -08001367 break;
1368 }
1369 }
1370 ++p;
1371 }
1372 }
1373 ++q;
1374 }
1375 // Flush the remaining string. This will be the entire
1376 // string if an entity wasn't found.
1377 if ( q-p > 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001378 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001379 }
Lee Thomason857b8682012-01-25 17:50:25 -08001380}
1381
U-Stream\Leeae25a442012-02-17 17:48:16 -08001382
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001383void XMLStreamer::PushHeader( bool writeBOM, bool writeDec )
1384{
1385 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1386 if ( writeBOM ) {
1387 Print( "%s", bom );
1388 }
1389 if ( writeDec ) {
1390 PushDeclaration( "xml version=\"1.0\"" );
1391 }
1392}
1393
1394
Lee Thomason56bdd022012-02-09 18:16:58 -08001395void XMLStreamer::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001396{
1397 if ( elementJustOpened ) {
1398 SealElement();
1399 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001400 stack.Push( name );
1401
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001402 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001403 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001404 PrintSpace( depth );
1405 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001406
U-Stream\Leeae25a442012-02-17 17:48:16 -08001407 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001408 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001409 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001410 ++depth;
1411}
1412
1413
1414void XMLStreamer::PushAttribute( const char* name, const char* value )
1415{
1416 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001417 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001418 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001419 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001420}
1421
1422
1423void XMLStreamer::CloseElement()
1424{
1425 --depth;
1426 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001427
1428 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001429 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001430 }
1431 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001432 if ( textDepth < 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001433 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001434 PrintSpace( depth );
1435 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001436 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001437 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001438
1439 if ( textDepth == depth )
1440 textDepth = -1;
1441 if ( depth == 0 )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001442 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001443 elementJustOpened = false;
1444}
1445
1446
1447void XMLStreamer::SealElement()
1448{
1449 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001450 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001451}
1452
1453
Lee Thomason50f97b22012-02-11 16:33:40 -08001454void XMLStreamer::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001455{
Lee Thomason56bdd022012-02-09 18:16:58 -08001456 textDepth = depth-1;
1457
Lee Thomason5cae8972012-01-24 18:03:07 -08001458 if ( elementJustOpened ) {
1459 SealElement();
1460 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001461 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001462 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001463 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001464 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001465 }
1466 else {
1467 PrintString( text, true );
1468 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001469}
1470
1471
1472void XMLStreamer::PushComment( const char* comment )
1473{
1474 if ( elementJustOpened ) {
1475 SealElement();
1476 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001477 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001478 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001479 PrintSpace( depth );
1480 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001481 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001482 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001483}
Lee Thomason751da522012-02-10 08:50:51 -08001484
1485
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001486void XMLStreamer::PushDeclaration( const char* value )
1487{
1488 if ( elementJustOpened ) {
1489 SealElement();
1490 }
1491 if ( textDepth < 0 && !firstElement) {
1492 Print( "\n" );
1493 PrintSpace( depth );
1494 }
1495 firstElement = false;
1496 Print( "<?%s?>", value );
1497}
1498
1499
1500void XMLStreamer::PushUnknown( const char* value )
1501{
1502 if ( elementJustOpened ) {
1503 SealElement();
1504 }
1505 if ( textDepth < 0 && !firstElement ) {
1506 Print( "\n" );
1507 PrintSpace( depth );
1508 }
1509 firstElement = false;
1510 Print( "<!%s>", value );
1511}
1512
1513
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001514bool XMLStreamer::VisitEnter( const XMLDocument& doc )
1515{
1516 if ( doc.HasBOM() ) {
1517 PushHeader( true, false );
1518 }
1519 return true;
1520}
1521
1522
Lee Thomason751da522012-02-10 08:50:51 -08001523bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
1524{
1525 OpenElement( element.Name() );
1526 while ( attribute ) {
1527 PushAttribute( attribute->Name(), attribute->Value() );
1528 attribute = attribute->Next();
1529 }
1530 return true;
1531}
1532
1533
1534bool XMLStreamer::VisitExit( const XMLElement& element )
1535{
1536 CloseElement();
1537 return true;
1538}
1539
1540
1541bool XMLStreamer::Visit( const XMLText& text )
1542{
Lee Thomasond6277762012-02-22 16:00:12 -08001543 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001544 return true;
1545}
1546
1547
1548bool XMLStreamer::Visit( const XMLComment& comment )
1549{
1550 PushComment( comment.Value() );
1551 return true;
1552}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001553
1554bool XMLStreamer::Visit( const XMLDeclaration& declaration )
1555{
1556 PushDeclaration( declaration.Value() );
1557 return true;
1558}
1559
1560
1561bool XMLStreamer::Visit( const XMLUnknown& unknown )
1562{
1563 PushUnknown( unknown.Value() );
1564 return true;
1565}
1566
1567