blob: 22cf5cbd2483a89371a516dffb4d6b163e3549e4 [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>
8
9//#pragma warning ( disable : 4291 )
U-Lama\Lee560bd472011-12-28 19:42:49 -080010
11using namespace tinyxml2;
12
Lee Thomasone4422302012-01-20 17:59:50 -080013static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080014static const char LF = LINE_FEED;
15static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
16static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080017static const char SINGLE_QUOTE = '\'';
18static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080019
Lee Thomason43f59302012-02-06 18:18:11 -080020#define DELETE_NODE( node ) { MemPool* pool = node->memPool; node->~XMLNode(); pool->Free( node ); }
21#define DELETE_ATTRIBUTE( attrib ) { MemPool* pool = attrib->memPool; attrib->~XMLAttribute(); pool->Free( attrib ); }
22
Lee Thomason8ee79892012-01-25 17:44:30 -080023struct Entity {
24 const char* pattern;
25 int length;
26 char value;
27};
28
29static const int NUM_ENTITIES = 5;
30static const Entity entities[NUM_ENTITIES] =
31{
Lee Thomason18d68bd2012-01-26 18:17:26 -080032 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080033 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080034 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080035 { "lt", 2, '<' },
36 { "gt", 2, '>' }
37};
38
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason1a1d4a72012-02-15 09:09:25 -080040StrPair::~StrPair()
41{
42 Reset();
43}
44
45
46void StrPair::Reset()
47{
48 if ( flags & NEEDS_DELETE ) {
49 delete [] start;
50 }
51 flags = 0;
52 start = 0;
53 end = 0;
54}
55
56
57void StrPair::SetStr( const char* str, int flags )
58{
59 Reset();
60 size_t len = strlen( str );
61 start = new char[ len+1 ];
62 strncpy( start, str, len );
63 end = start + len;
64 this->flags = flags | NEEDS_DELETE;
65}
66
67
68char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
69{
70 TIXMLASSERT( endTag && *endTag );
71
72 char* start = p; // fixme: hides a member
73 char endChar = *endTag;
74 int length = strlen( endTag );
75
76 // Inner loop of text parsing.
77 while ( *p ) {
78 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
79 Set( start, p, strFlags );
80 return p + length;
81 }
82 ++p;
83 }
84 return p;
85}
86
87
88char* StrPair::ParseName( char* p )
89{
90 char* start = p;
91
92 start = p;
93 if ( !start || !(*start) ) {
94 return 0;
95 }
96
97 if ( !XMLUtil::IsAlpha( *p ) ) {
98 return 0;
99 }
100
101 while( *p && (
102 XMLUtil::IsAlphaNum( (unsigned char) *p )
103 || *p == '_'
104 || *p == '-'
105 || *p == '.'
106 || *p == ':' ))
107 {
108 ++p;
109 }
110
111 if ( p > start ) {
112 Set( start, p, 0 );
113 return p;
114 }
115 return 0;
116}
117
118
Lee Thomasone4422302012-01-20 17:59:50 -0800119const char* StrPair::GetStr()
120{
121 if ( flags & NEEDS_FLUSH ) {
122 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800123 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800124
Lee Thomason8ee79892012-01-25 17:44:30 -0800125 if ( flags ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800126 char* p = start;
127 char* q = start;
128
129 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800130 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800131 // CR-LF pair becomes LF
132 // CR alone becomes LF
133 // LF-CR becomes LF
134 if ( *(p+1) == LF ) {
135 p += 2;
136 }
137 else {
138 ++p;
139 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800140 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800141 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800142 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800143 if ( *(p+1) == CR ) {
144 p += 2;
145 }
146 else {
147 ++p;
148 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800149 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800150 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800151 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
152 int i=0;
153 for( i=0; i<NUM_ENTITIES; ++i ) {
154 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
155 && *(p+entities[i].length+1) == ';' )
156 {
157 // Found an entity convert;
158 *q = entities[i].value;
159 ++q;
160 p += entities[i].length + 2;
161 break;
162 }
163 }
164 if ( i == NUM_ENTITIES ) {
165 // fixme: treat as error?
166 ++p;
167 ++q;
168 }
169 }
Lee Thomasone4422302012-01-20 17:59:50 -0800170 else {
171 *q = *p;
172 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800173 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800174 }
175 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800176 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800177 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800178 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800179 }
180 return start;
181}
182
Lee Thomason2c85a712012-01-31 08:24:24 -0800183
Lee Thomasone4422302012-01-20 17:59:50 -0800184
Lee Thomason56bdd022012-02-09 18:16:58 -0800185// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800186
Lee Thomasond1983222012-02-06 08:41:24 -0800187char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800188{
189 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800190 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800191 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800192 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800193 {
194 return 0;
195 }
196
197 // What is this thing?
198 // - Elements start with a letter or underscore, but xml is reserved.
199 // - Comments: <!--
200 // - Decleration: <?xml
201 // - Everthing else is unknown to tinyxml.
202 //
203
204 static const char* xmlHeader = { "<?xml" };
205 static const char* commentHeader = { "<!--" };
206 static const char* dtdHeader = { "<!" };
207 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800208 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800209
210 static const int xmlHeaderLen = 5;
211 static const int commentHeaderLen = 4;
212 static const int dtdHeaderLen = 2;
213 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800214 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800215
Lee Thomason50f97b22012-02-11 16:33:40 -0800216 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
217 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
218
219 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
220 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
221 returnNode->memPool = &commentPool;
222 p += xmlHeaderLen;
223 }
224 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800225 returnNode = new (commentPool.Alloc()) XMLComment( this );
226 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800227 p += commentHeaderLen;
228 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800229 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
230 XMLText* text = new (textPool.Alloc()) XMLText( this );
231 returnNode = text;
232 returnNode->memPool = &textPool;
233 p += cdataHeaderLen;
234 text->SetCData( true );
235 }
236 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
237 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
238 returnNode->memPool = &commentPool;
239 p += dtdHeaderLen;
240 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800241 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800242 returnNode = new (elementPool.Alloc()) XMLElement( this );
243 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800244 p += elementHeaderLen;
245 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800246 else if ( (*p != '<') && XMLUtil::IsAlphaNum( *p ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800247 returnNode = new (textPool.Alloc()) XMLText( this );
248 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800249 p = start; // Back it up, all the text counts.
250 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800251 else {
Lee Thomason50f97b22012-02-11 16:33:40 -0800252 this->SetError( ERROR_IDENTIFYING_TAG, p, 0 );
253 p = 0;
254 returnNode = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800255 }
256
257 *node = returnNode;
258 return p;
259}
260
261
Lee Thomason751da522012-02-10 08:50:51 -0800262bool XMLDocument::Accept( XMLVisitor* visitor ) const
263{
264 if ( visitor->VisitEnter( *this ) )
265 {
266 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
267 {
268 if ( !node->Accept( visitor ) )
269 break;
270 }
271 }
272 return visitor->VisitExit( *this );
273}
Lee Thomason56bdd022012-02-09 18:16:58 -0800274
275
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800276// --------- XMLNode ----------- //
277
278XMLNode::XMLNode( XMLDocument* doc ) :
279 document( doc ),
280 parent( 0 ),
281 firstChild( 0 ), lastChild( 0 ),
282 prev( 0 ), next( 0 )
283{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800284}
285
286
287XMLNode::~XMLNode()
288{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800289 ClearChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800290 if ( parent ) {
291 parent->Unlink( this );
292 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800293}
294
295
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800296void XMLNode::SetValue( const char* str, bool staticMem )
297{
298 if ( staticMem )
299 value.SetInternedStr( str );
300 else
301 value.SetStr( str );
302}
303
304
Lee Thomason18d68bd2012-01-26 18:17:26 -0800305void XMLNode::ClearChildren()
306{
Lee Thomasond923c672012-01-23 08:44:25 -0800307 while( firstChild ) {
308 XMLNode* node = firstChild;
309 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800310
Lee Thomason43f59302012-02-06 18:18:11 -0800311 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800312 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800313 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800314}
315
316
317void XMLNode::Unlink( XMLNode* child )
318{
319 TIXMLASSERT( child->parent == this );
320 if ( child == firstChild )
321 firstChild = firstChild->next;
322 if ( child == lastChild )
323 lastChild = lastChild->prev;
324
325 if ( child->prev ) {
326 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800327 }
Lee Thomasond923c672012-01-23 08:44:25 -0800328 if ( child->next ) {
329 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800330 }
Lee Thomasond923c672012-01-23 08:44:25 -0800331 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800332}
333
334
335XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
336{
337 if ( lastChild ) {
338 TIXMLASSERT( firstChild );
339 TIXMLASSERT( lastChild->next == 0 );
340 lastChild->next = addThis;
341 addThis->prev = lastChild;
342 lastChild = addThis;
343
344 addThis->parent = this;
345 addThis->next = 0;
346 }
347 else {
348 TIXMLASSERT( firstChild == 0 );
349 firstChild = lastChild = addThis;
350
351 addThis->parent = this;
352 addThis->prev = 0;
353 addThis->next = 0;
354 }
355 return addThis;
356}
357
358
Lee Thomason1ff38e02012-02-14 18:18:16 -0800359XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
360{
361 if ( firstChild ) {
362 TIXMLASSERT( lastChild );
363 TIXMLASSERT( firstChild->prev == 0 );
364
365 firstChild->prev = addThis;
366 addThis->next = firstChild;
367 firstChild = addThis;
368
369 addThis->parent = this;
370 addThis->prev = 0;
371 }
372 else {
373 TIXMLASSERT( lastChild == 0 );
374 firstChild = lastChild = addThis;
375
376 addThis->parent = this;
377 addThis->prev = 0;
378 addThis->next = 0;
379 }
380 return addThis;
381}
382
383
384XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
385{
386 TIXMLASSERT( afterThis->parent == this );
387 if ( afterThis->parent != this )
388 return 0;
389
390 if ( afterThis->next == 0 ) {
391 // The last node or the only node.
392 return InsertEndChild( addThis );
393 }
394 addThis->prev = afterThis;
395 addThis->next = afterThis->next;
396 afterThis->next->prev = addThis;
397 afterThis->next = addThis;
398 return addThis;
399}
400
401
402
403
Lee Thomason56bdd022012-02-09 18:16:58 -0800404const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800405{
406 for( XMLNode* node=firstChild; node; node=node->next ) {
407 XMLElement* element = node->ToElement();
408 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800409 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800410 return element;
411 }
412 }
413 }
414 return 0;
415}
416
417
Lee Thomason56bdd022012-02-09 18:16:58 -0800418const XMLElement* XMLNode::LastChildElement( const char* value ) const
419{
420 for( XMLNode* node=lastChild; node; node=node->prev ) {
421 XMLElement* element = node->ToElement();
422 if ( element ) {
423 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
424 return element;
425 }
426 }
427 }
428 return 0;
429}
430
431
432void XMLNode::DeleteChild( XMLNode* node )
433{
434 TIXMLASSERT( node->parent == this );
435 TIXMLASSERT( 0 );
436}
437
438
Lee Thomason67d61312012-01-24 16:01:51 -0800439char* XMLNode::ParseDeep( char* p )
440{
441 while( p && *p ) {
442 XMLNode* node = 0;
Lee Thomasond1983222012-02-06 08:41:24 -0800443 p = document->Identify( p, &node );
Lee Thomason67d61312012-01-24 16:01:51 -0800444 if ( p && node ) {
445 p = node->ParseDeep( p );
446 // FIXME: is it the correct closing element?
447 if ( node->IsClosingElement() ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800448 DELETE_NODE( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800449 return p;
450 }
451 this->InsertEndChild( node );
452 }
453 }
454 return 0;
455}
456
Lee Thomason5492a1c2012-01-23 15:32:10 -0800457// --------- XMLText ---------- //
458char* XMLText::ParseDeep( char* p )
459{
Lee Thomason50f97b22012-02-11 16:33:40 -0800460 if ( this->CData() ) {
461 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
462 return p;
463 }
464 else {
465 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
466 // consumes the end tag.
467 if ( p && *p ) {
468 return p-1;
469 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800470 }
471 return 0;
472}
473
474
Lee Thomason56bdd022012-02-09 18:16:58 -0800475bool XMLText::Accept( XMLVisitor* visitor ) const
476{
477 return visitor->Visit( *this );
478}
479
480
Lee Thomason3f57d272012-01-11 15:30:03 -0800481// --------- XMLComment ---------- //
482
Lee Thomasone4422302012-01-20 17:59:50 -0800483XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800484{
485}
486
487
Lee Thomasonce0763e2012-01-11 15:43:54 -0800488XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800489{
Lee Thomasond923c672012-01-23 08:44:25 -0800490 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800491}
492
493
Lee Thomasonce0763e2012-01-11 15:43:54 -0800494char* XMLComment::ParseDeep( char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800495{
496 // Comment parses as text.
Lee Thomason56bdd022012-02-09 18:16:58 -0800497 return value.ParseText( p, "-->", StrPair::COMMENT );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800498}
499
500
Lee Thomason751da522012-02-10 08:50:51 -0800501bool XMLComment::Accept( XMLVisitor* visitor ) const
502{
503 return visitor->Visit( *this );
504}
Lee Thomason56bdd022012-02-09 18:16:58 -0800505
506
Lee Thomason50f97b22012-02-11 16:33:40 -0800507// --------- XMLDeclaration ---------- //
508
509XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
510{
511}
512
513
514XMLDeclaration::~XMLDeclaration()
515{
516 //printf( "~XMLDeclaration\n" );
517}
518
519
520char* XMLDeclaration::ParseDeep( char* p )
521{
522 // Declaration parses as text.
523 return value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
524}
525
526
527bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
528{
529 return visitor->Visit( *this );
530}
531
532// --------- XMLUnknown ---------- //
533
534XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
535{
536}
537
538
539XMLUnknown::~XMLUnknown()
540{
541}
542
543
544char* XMLUnknown::ParseDeep( char* p )
545{
546 // Unknown parses as text.
547 return value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
548}
549
550
551bool XMLUnknown::Accept( XMLVisitor* visitor ) const
552{
553 return visitor->Visit( *this );
554}
555
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800556// --------- XMLAttribute ---------- //
557char* XMLAttribute::ParseDeep( char* p )
558{
Lee Thomason56bdd022012-02-09 18:16:58 -0800559 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800560 if ( !p || !*p ) return 0;
561
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562 char endTag[2] = { *p, 0 };
563 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800564 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomasone4422302012-01-20 17:59:50 -0800565 if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800566 return p;
567}
568
569
Lee Thomason1ff38e02012-02-14 18:18:16 -0800570int XMLAttribute::QueryIntAttribute( int* value ) const
571{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800572 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
573 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800574 return WRONG_ATTRIBUTE_TYPE;
575}
576
577
578int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
579{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800580 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
581 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800582 return WRONG_ATTRIBUTE_TYPE;
583}
584
585
586int XMLAttribute::QueryBoolAttribute( bool* value ) const
587{
588 int ival = -1;
589 QueryIntAttribute( &ival );
590
591 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
592 *value = true;
593 return ATTRIBUTE_SUCCESS;
594 }
595 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
596 *value = false;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800597 return ATTRIBUTE_SUCCESS;
598 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800599 return WRONG_ATTRIBUTE_TYPE;
600}
601
602
603int XMLAttribute::QueryDoubleAttribute( double* value ) const
604{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800605 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
606 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800607 return WRONG_ATTRIBUTE_TYPE;
608}
609
610
611int XMLAttribute::QueryFloatAttribute( float* value ) const
612{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800613 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
614 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800615 return WRONG_ATTRIBUTE_TYPE;
616}
617
618
619void XMLAttribute::SetAttribute( const char* v )
620{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800621 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800622}
623
624
Lee Thomason1ff38e02012-02-14 18:18:16 -0800625void XMLAttribute::SetAttribute( int v )
626{
627 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800628 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
629 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800630}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800631
632
633void XMLAttribute::SetAttribute( unsigned v )
634{
635 char buf[BUF_SIZE];
636 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
637 value.SetStr( buf );
638}
639
640
641void XMLAttribute::SetAttribute( bool v )
642{
643 char buf[BUF_SIZE];
644 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
645 value.SetStr( buf );
646}
647
648void XMLAttribute::SetAttribute( double v )
649{
650 char buf[BUF_SIZE];
651 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
652 value.SetStr( buf );
653}
654
655void XMLAttribute::SetAttribute( float v )
656{
657 char buf[BUF_SIZE];
658 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
659 value.SetStr( buf );
660}
661
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800662
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663// --------- XMLElement ---------- //
664XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800665 closing( false ),
666 rootAttribute( 0 ),
667 lastAttribute( 0 )
668{
669}
670
671
672XMLElement::~XMLElement()
673{
674 XMLAttribute* attribute = rootAttribute;
675 while( attribute ) {
676 XMLAttribute* next = attribute->next;
Lee Thomason43f59302012-02-06 18:18:11 -0800677 DELETE_ATTRIBUTE( attribute );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678 attribute = next;
679 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680}
681
682
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800683XMLAttribute* XMLElement::FindAttribute( const char* name )
684{
685 XMLAttribute* a = 0;
686 for( a=rootAttribute; a; a = a->next ) {
687 if ( XMLUtil::StringEqual( a->Name(), name ) )
688 return a;
689 }
690 return 0;
691}
692
693
694const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
695{
696 XMLAttribute* a = 0;
697 for( a=rootAttribute; a; a = a->next ) {
698 if ( XMLUtil::StringEqual( a->Name(), name ) )
699 return a;
700 }
701 return 0;
702}
703
704
705XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
706{
707 XMLAttribute* attrib = FindAttribute( name );
708 if ( !attrib ) {
709 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
710 attrib->memPool = &document->attributePool;
711 }
712 return attrib;
713}
714
715
Lee Thomason67d61312012-01-24 16:01:51 -0800716char* XMLElement::ParseAttributes( char* p, bool* closedElement )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718 const char* start = p;
Lee Thomason67d61312012-01-24 16:01:51 -0800719 *closedElement = false;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800720
721 // Read the attributes.
722 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800723 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800724 if ( !p || !(*p) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800725 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800726 return 0;
727 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728
729 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -0800730 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800731 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
732 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -0800733
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800734 p = attrib->ParseDeep( p );
735 if ( !p ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800736 DELETE_ATTRIBUTE( attrib );
Lee Thomasone4422302012-01-20 17:59:50 -0800737 document->SetError( XMLDocument::ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800738 return 0;
739 }
740 if ( rootAttribute ) {
741 TIXMLASSERT( lastAttribute );
742 lastAttribute->next = attrib;
743 lastAttribute = attrib;
744 }
745 else {
746 rootAttribute = lastAttribute = attrib;
747 }
748 }
Lee Thomasone4422302012-01-20 17:59:50 -0800749 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751 if ( closing ) {
752 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
753 return 0;
754 }
Lee Thomason67d61312012-01-24 16:01:51 -0800755 *closedElement = true;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800756 return p+2; // done; sealed element.
757 }
Lee Thomasone4422302012-01-20 17:59:50 -0800758 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800759 else if ( *p == '>' ) {
760 ++p;
761 break;
762 }
Lee Thomasone4422302012-01-20 17:59:50 -0800763 else {
764 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
765 return 0;
766 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800767 }
Lee Thomason67d61312012-01-24 16:01:51 -0800768 return p;
769}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800770
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800771
Lee Thomason67d61312012-01-24 16:01:51 -0800772//
773// <ele></ele>
774// <ele>foo<b>bar</b></ele>
775//
776char* XMLElement::ParseDeep( char* p )
777{
778 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800779 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -0800780 if ( !p ) return 0;
781 const char* start = p;
782
783 // The closing element is the </element> form. It is
784 // parsed just like a regular element then deleted from
785 // the DOM.
786 if ( *p == '/' ) {
787 closing = true;
788 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800789 }
Lee Thomason67d61312012-01-24 16:01:51 -0800790
Lee Thomason56bdd022012-02-09 18:16:58 -0800791 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -0800792 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800793
794 bool elementClosed=false;
795 p = ParseAttributes( p, &elementClosed );
796 if ( !p || !*p || elementClosed || closing )
797 return p;
798
799 p = XMLNode::ParseDeep( p );
800 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801}
802
803
Lee Thomason751da522012-02-10 08:50:51 -0800804bool XMLElement::Accept( XMLVisitor* visitor ) const
805{
806 if ( visitor->VisitEnter( *this, rootAttribute ) )
807 {
808 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
809 {
810 if ( !node->Accept( visitor ) )
811 break;
812 }
813 }
814 return visitor->VisitExit( *this );
815
816}
Lee Thomason56bdd022012-02-09 18:16:58 -0800817
818
Lee Thomason3f57d272012-01-11 15:30:03 -0800819// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -0800820XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -0800821 XMLNode( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -0800822 charBuffer( 0 )
823{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800824 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -0800825}
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800826
827
Lee Thomason3f57d272012-01-11 15:30:03 -0800828XMLDocument::~XMLDocument()
829{
Lee Thomasond1983222012-02-06 08:41:24 -0800830 ClearChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -0800831 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -0800832
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800833#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -0800834 textPool.Trace( "text" );
835 elementPool.Trace( "element" );
836 commentPool.Trace( "comment" );
837 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800838#endif
839
Lee Thomason455c9d42012-02-06 09:14:14 -0800840 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
841 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
842 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
843 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -0800844}
845
846
Lee Thomason18d68bd2012-01-26 18:17:26 -0800847void XMLDocument::InitDocument()
848{
849 errorID = NO_ERROR;
850 errorStr1 = 0;
851 errorStr2 = 0;
852
853 delete [] charBuffer;
854 charBuffer = 0;
855
856}
857
Lee Thomason3f57d272012-01-11 15:30:03 -0800858
Lee Thomason2c85a712012-01-31 08:24:24 -0800859XMLElement* XMLDocument::NewElement( const char* name )
860{
Lee Thomasond1983222012-02-06 08:41:24 -0800861 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
862 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -0800863 ele->SetName( name );
864 return ele;
865}
866
867
Lee Thomason1ff38e02012-02-14 18:18:16 -0800868XMLComment* XMLDocument::NewComment( const char* str )
869{
870 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
871 comment->memPool = &commentPool;
872 comment->SetValue( str );
873 return comment;
874}
875
876
877XMLText* XMLDocument::NewText( const char* str )
878{
879 XMLText* Text = new (textPool.Alloc()) XMLText( this );
880 Text->memPool = &textPool;
881 Text->SetValue( str );
882 return Text;
883}
884
885
886
Lee Thomason7c913cd2012-01-26 18:32:34 -0800887int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800888{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800889 ClearChildren();
890 InitDocument();
891
892 if ( !p || !*p ) {
893 return true; // correctly parse an empty string?
894 }
895 size_t len = strlen( p );
896 charBuffer = new char[ len+1 ];
897 memcpy( charBuffer, p, len+1 );
Lee Thomason3f57d272012-01-11 15:30:03 -0800898 XMLNode* node = 0;
Lee Thomason85403d82012-01-11 15:55:05 -0800899
Lee Thomason18d68bd2012-01-26 18:17:26 -0800900 char* q = ParseDeep( charBuffer );
Lee Thomason7c913cd2012-01-26 18:32:34 -0800901 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -0800902}
903
904
Lee Thomason5cae8972012-01-24 18:03:07 -0800905void XMLDocument::Print( XMLStreamer* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -0800906{
Lee Thomason5cae8972012-01-24 18:03:07 -0800907 XMLStreamer stdStreamer( stdout );
908 if ( !streamer )
909 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -0800910 //for( XMLNode* node = firstChild; node; node=node->next ) {
911 // node->Print( streamer );
912 //}
913 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -0800914}
915
916
Lee Thomason67d61312012-01-24 16:01:51 -0800917void XMLDocument::SetError( int error, const char* str1, const char* str2 )
918{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800919 errorID = error;
920 printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 ); // fixme: remove
921 errorStr1 = str1;
922 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -0800923}
924
Lee Thomason5cae8972012-01-24 18:03:07 -0800925
Lee Thomason2c85a712012-01-31 08:24:24 -0800926/*
Lee Thomason5cae8972012-01-24 18:03:07 -0800927StringStack::StringStack()
928{
Lee Thomason5cae8972012-01-24 18:03:07 -0800929 nPositive = 0;
Lee Thomason1270ae52012-01-27 17:58:30 -0800930 mem.Push( 0 ); // start with null. makes later code simpler.
Lee Thomason5cae8972012-01-24 18:03:07 -0800931}
932
933
Lee Thomason24767b02012-01-25 17:16:23 -0800934StringStack::~StringStack()
935{
Lee Thomason24767b02012-01-25 17:16:23 -0800936}
937
938
Lee Thomason5cae8972012-01-24 18:03:07 -0800939void StringStack::Push( const char* str ) {
940 int needed = strlen( str ) + 1;
Lee Thomason1270ae52012-01-27 17:58:30 -0800941 char* p = mem.PushArr( needed );
942 strcpy( p, str );
943 if ( needed > 1 )
Lee Thomason5cae8972012-01-24 18:03:07 -0800944 nPositive++;
Lee Thomason5cae8972012-01-24 18:03:07 -0800945}
946
947
948const char* StringStack::Pop() {
Lee Thomason1270ae52012-01-27 17:58:30 -0800949 TIXMLASSERT( mem.Size() > 1 );
950 const char* p = mem.Mem() + mem.Size() - 2; // end of final string.
Lee Thomason5cae8972012-01-24 18:03:07 -0800951 if ( *p ) {
952 nPositive--;
953 }
954 while( *p ) { // stack starts with a null, don't need to check for 'mem'
Lee Thomason1270ae52012-01-27 17:58:30 -0800955 TIXMLASSERT( p > mem.Mem() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800956 --p;
957 }
Lee Thomason1270ae52012-01-27 17:58:30 -0800958 mem.PopArr( strlen(p)+1 );
Lee Thomason5cae8972012-01-24 18:03:07 -0800959 return p+1;
960}
Lee Thomason2c85a712012-01-31 08:24:24 -0800961*/
Lee Thomason5cae8972012-01-24 18:03:07 -0800962
963
Lee Thomason56bdd022012-02-09 18:16:58 -0800964XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false ), textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -0800965{
Lee Thomason857b8682012-01-25 17:50:25 -0800966 for( int i=0; i<ENTITY_RANGE; ++i ) {
967 entityFlag[i] = false;
968 }
969 for( int i=0; i<NUM_ENTITIES; ++i ) {
970 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
971 if ( entities[i].value < ENTITY_RANGE ) {
972 entityFlag[ entities[i].value ] = true;
973 }
974 }
Lee Thomason5cae8972012-01-24 18:03:07 -0800975}
976
977
978void XMLStreamer::PrintSpace( int depth )
979{
980 for( int i=0; i<depth; ++i ) {
981 fprintf( fp, " " );
982 }
983}
984
985
Lee Thomason951d8832012-01-26 08:47:06 -0800986void XMLStreamer::PrintString( const char* p )
Lee Thomason857b8682012-01-25 17:50:25 -0800987{
Lee Thomason951d8832012-01-26 08:47:06 -0800988 // Look for runs of bytes between entities to print.
989 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -0800990
Lee Thomason951d8832012-01-26 08:47:06 -0800991 while ( *q ) {
992 if ( *q < ENTITY_RANGE ) {
993 // Check for entities. If one is found, flush
994 // the stream up until the entity, write the
995 // entity, and keep looking.
996 if ( entityFlag[*q] ) {
997 while ( p < q ) {
998 fputc( *p, fp );
999 ++p;
1000 }
1001 for( int i=0; i<NUM_ENTITIES; ++i ) {
1002 if ( entities[i].value == *q ) {
1003 fprintf( fp, "&%s;", entities[i].pattern );
1004 break;
1005 }
1006 }
1007 ++p;
1008 }
1009 }
1010 ++q;
1011 }
1012 // Flush the remaining string. This will be the entire
1013 // string if an entity wasn't found.
1014 if ( q-p > 0 ) {
1015 fprintf( fp, "%s", p );
1016 }
Lee Thomason857b8682012-01-25 17:50:25 -08001017}
1018
Lee Thomason56bdd022012-02-09 18:16:58 -08001019void XMLStreamer::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001020{
1021 if ( elementJustOpened ) {
1022 SealElement();
1023 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001024 stack.Push( name );
1025
1026 if ( textDepth < 0 && depth > 0) {
1027 fprintf( fp, "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001028 PrintSpace( depth );
1029 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001030
Lee Thomason5cae8972012-01-24 18:03:07 -08001031 fprintf( fp, "<%s", name );
1032 elementJustOpened = true;
1033 ++depth;
1034}
1035
1036
1037void XMLStreamer::PushAttribute( const char* name, const char* value )
1038{
1039 TIXMLASSERT( elementJustOpened );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001040 fprintf( fp, " %s=\"", name );
1041 PrintString( value );
1042 fprintf( fp, "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001043}
1044
1045
1046void XMLStreamer::CloseElement()
1047{
1048 --depth;
1049 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001050
1051 if ( elementJustOpened ) {
1052 fprintf( fp, "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001053 }
1054 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001055 if ( textDepth < 0 ) {
1056 fprintf( fp, "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001057 PrintSpace( depth );
1058 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001059 fprintf( fp, "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001060 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001061
1062 if ( textDepth == depth )
1063 textDepth = -1;
1064 if ( depth == 0 )
1065 fprintf( fp, "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001066 elementJustOpened = false;
1067}
1068
1069
1070void XMLStreamer::SealElement()
1071{
1072 elementJustOpened = false;
1073 fprintf( fp, ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001074}
1075
1076
Lee Thomason50f97b22012-02-11 16:33:40 -08001077void XMLStreamer::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001078{
Lee Thomason56bdd022012-02-09 18:16:58 -08001079 textDepth = depth-1;
1080
Lee Thomason5cae8972012-01-24 18:03:07 -08001081 if ( elementJustOpened ) {
1082 SealElement();
1083 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001084 if ( cdata )
1085 fprintf( fp, "<![CDATA[" );
Lee Thomason951d8832012-01-26 08:47:06 -08001086 PrintString( text );
Lee Thomason50f97b22012-02-11 16:33:40 -08001087 if ( cdata )
1088 fprintf( fp, "]]>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001089}
1090
1091
1092void XMLStreamer::PushComment( const char* comment )
1093{
1094 if ( elementJustOpened ) {
1095 SealElement();
1096 }
1097 PrintSpace( depth );
1098 fprintf( fp, "<!--%s-->\n", comment );
1099}
Lee Thomason751da522012-02-10 08:50:51 -08001100
1101
1102bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
1103{
1104 OpenElement( element.Name() );
1105 while ( attribute ) {
1106 PushAttribute( attribute->Name(), attribute->Value() );
1107 attribute = attribute->Next();
1108 }
1109 return true;
1110}
1111
1112
1113bool XMLStreamer::VisitExit( const XMLElement& element )
1114{
1115 CloseElement();
1116 return true;
1117}
1118
1119
1120bool XMLStreamer::Visit( const XMLText& text )
1121{
1122 PushText( text.Value() );
1123 return true;
1124}
1125
1126
1127bool XMLStreamer::Visit( const XMLComment& comment )
1128{
1129 PushComment( comment.Value() );
1130 return true;
1131}