blob: 3a9b2c94d546c91bdbd79c2a7f5c9201fa1e4ca0 [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 Thomason43f59302012-02-06 18:18:11 -080021#define DELETE_NODE( node ) { MemPool* pool = node->memPool; node->~XMLNode(); pool->Free( node ); }
22#define DELETE_ATTRIBUTE( attrib ) { MemPool* pool = attrib->memPool; attrib->~XMLAttribute(); pool->Free( attrib ); }
23
Lee Thomason8ee79892012-01-25 17:44:30 -080024struct Entity {
25 const char* pattern;
26 int length;
27 char value;
28};
29
30static const int NUM_ENTITIES = 5;
31static const Entity entities[NUM_ENTITIES] =
32{
Lee Thomason18d68bd2012-01-26 18:17:26 -080033 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080034 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080035 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080036 { "lt", 2, '<' },
37 { "gt", 2, '>' }
38};
39
Lee Thomasonfde6a752012-01-14 18:08:12 -080040
Lee Thomason1a1d4a72012-02-15 09:09:25 -080041StrPair::~StrPair()
42{
43 Reset();
44}
45
46
47void StrPair::Reset()
48{
49 if ( flags & NEEDS_DELETE ) {
50 delete [] start;
51 }
52 flags = 0;
53 start = 0;
54 end = 0;
55}
56
57
58void StrPair::SetStr( const char* str, int flags )
59{
60 Reset();
61 size_t len = strlen( str );
62 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -080063 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080064 end = start + len;
65 this->flags = flags | NEEDS_DELETE;
66}
67
68
69char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
70{
71 TIXMLASSERT( endTag && *endTag );
72
73 char* start = p; // fixme: hides a member
74 char endChar = *endTag;
75 int length = strlen( endTag );
76
77 // Inner loop of text parsing.
78 while ( *p ) {
79 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
80 Set( start, p, strFlags );
81 return p + length;
82 }
83 ++p;
84 }
85 return p;
86}
87
88
89char* StrPair::ParseName( char* p )
90{
91 char* start = p;
92
93 start = p;
94 if ( !start || !(*start) ) {
95 return 0;
96 }
97
98 if ( !XMLUtil::IsAlpha( *p ) ) {
99 return 0;
100 }
101
102 while( *p && (
103 XMLUtil::IsAlphaNum( (unsigned char) *p )
104 || *p == '_'
105 || *p == '-'
106 || *p == '.'
107 || *p == ':' ))
108 {
109 ++p;
110 }
111
112 if ( p > start ) {
113 Set( start, p, 0 );
114 return p;
115 }
116 return 0;
117}
118
119
Lee Thomasone4422302012-01-20 17:59:50 -0800120const char* StrPair::GetStr()
121{
122 if ( flags & NEEDS_FLUSH ) {
123 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800124 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800125
Lee Thomason8ee79892012-01-25 17:44:30 -0800126 if ( flags ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800127 char* p = start;
128 char* q = start;
129
130 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800131 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800132 // CR-LF pair becomes LF
133 // CR alone becomes LF
134 // LF-CR becomes LF
135 if ( *(p+1) == LF ) {
136 p += 2;
137 }
138 else {
139 ++p;
140 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800141 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800142 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800143 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800144 if ( *(p+1) == CR ) {
145 p += 2;
146 }
147 else {
148 ++p;
149 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800150 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800151 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800152 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
153 int i=0;
154 for( i=0; i<NUM_ENTITIES; ++i ) {
155 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
156 && *(p+entities[i].length+1) == ';' )
157 {
158 // Found an entity convert;
159 *q = entities[i].value;
160 ++q;
161 p += entities[i].length + 2;
162 break;
163 }
164 }
165 if ( i == NUM_ENTITIES ) {
166 // fixme: treat as error?
167 ++p;
168 ++q;
169 }
170 }
Lee Thomasone4422302012-01-20 17:59:50 -0800171 else {
172 *q = *p;
173 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800174 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800175 }
176 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800177 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800178 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800179 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800180 }
181 return start;
182}
183
Lee Thomason2c85a712012-01-31 08:24:24 -0800184
Lee Thomasone4422302012-01-20 17:59:50 -0800185
Lee Thomason56bdd022012-02-09 18:16:58 -0800186// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800187
Lee Thomasond1983222012-02-06 08:41:24 -0800188char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800189{
190 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800191 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800192 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800193 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800194 {
195 return 0;
196 }
197
198 // What is this thing?
199 // - Elements start with a letter or underscore, but xml is reserved.
200 // - Comments: <!--
201 // - Decleration: <?xml
202 // - Everthing else is unknown to tinyxml.
203 //
204
205 static const char* xmlHeader = { "<?xml" };
206 static const char* commentHeader = { "<!--" };
207 static const char* dtdHeader = { "<!" };
208 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800209 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800210
211 static const int xmlHeaderLen = 5;
212 static const int commentHeaderLen = 4;
213 static const int dtdHeaderLen = 2;
214 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800215 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800216
Lee Thomason50f97b22012-02-11 16:33:40 -0800217 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
218 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
219
220 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
221 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
222 returnNode->memPool = &commentPool;
223 p += xmlHeaderLen;
224 }
225 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800226 returnNode = new (commentPool.Alloc()) XMLComment( this );
227 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800228 p += commentHeaderLen;
229 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800230 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
231 XMLText* text = new (textPool.Alloc()) XMLText( this );
232 returnNode = text;
233 returnNode->memPool = &textPool;
234 p += cdataHeaderLen;
235 text->SetCData( true );
236 }
237 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
238 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
239 returnNode->memPool = &commentPool;
240 p += dtdHeaderLen;
241 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800242 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800243 returnNode = new (elementPool.Alloc()) XMLElement( this );
244 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800245 p += elementHeaderLen;
246 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800247 else if ( (*p != '<') && XMLUtil::IsAlphaNum( *p ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800248 returnNode = new (textPool.Alloc()) XMLText( this );
249 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800250 p = start; // Back it up, all the text counts.
251 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800252 else {
Lee Thomason50f97b22012-02-11 16:33:40 -0800253 this->SetError( ERROR_IDENTIFYING_TAG, p, 0 );
254 p = 0;
255 returnNode = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800256 }
257
258 *node = returnNode;
259 return p;
260}
261
262
Lee Thomason751da522012-02-10 08:50:51 -0800263bool XMLDocument::Accept( XMLVisitor* visitor ) const
264{
265 if ( visitor->VisitEnter( *this ) )
266 {
267 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
268 {
269 if ( !node->Accept( visitor ) )
270 break;
271 }
272 }
273 return visitor->VisitExit( *this );
274}
Lee Thomason56bdd022012-02-09 18:16:58 -0800275
276
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800277// --------- XMLNode ----------- //
278
279XMLNode::XMLNode( XMLDocument* doc ) :
280 document( doc ),
281 parent( 0 ),
282 firstChild( 0 ), lastChild( 0 ),
283 prev( 0 ), next( 0 )
284{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800285}
286
287
288XMLNode::~XMLNode()
289{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800290 ClearChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800291 if ( parent ) {
292 parent->Unlink( this );
293 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800294}
295
296
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800297void XMLNode::SetValue( const char* str, bool staticMem )
298{
299 if ( staticMem )
300 value.SetInternedStr( str );
301 else
302 value.SetStr( str );
303}
304
305
Lee Thomason18d68bd2012-01-26 18:17:26 -0800306void XMLNode::ClearChildren()
307{
Lee Thomasond923c672012-01-23 08:44:25 -0800308 while( firstChild ) {
309 XMLNode* node = firstChild;
310 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800311
Lee Thomason43f59302012-02-06 18:18:11 -0800312 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800313 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800314 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800315}
316
317
318void XMLNode::Unlink( XMLNode* child )
319{
320 TIXMLASSERT( child->parent == this );
321 if ( child == firstChild )
322 firstChild = firstChild->next;
323 if ( child == lastChild )
324 lastChild = lastChild->prev;
325
326 if ( child->prev ) {
327 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800328 }
Lee Thomasond923c672012-01-23 08:44:25 -0800329 if ( child->next ) {
330 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800331 }
Lee Thomasond923c672012-01-23 08:44:25 -0800332 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800333}
334
335
U-Stream\Leeae25a442012-02-17 17:48:16 -0800336void XMLNode::DeleteChild( XMLNode* node )
337{
338 TIXMLASSERT( node->parent == this );
339 DELETE_NODE( node );
340}
341
342
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800343XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
344{
345 if ( lastChild ) {
346 TIXMLASSERT( firstChild );
347 TIXMLASSERT( lastChild->next == 0 );
348 lastChild->next = addThis;
349 addThis->prev = lastChild;
350 lastChild = addThis;
351
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800352 addThis->next = 0;
353 }
354 else {
355 TIXMLASSERT( firstChild == 0 );
356 firstChild = lastChild = addThis;
357
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800358 addThis->prev = 0;
359 addThis->next = 0;
360 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800361 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800362 return addThis;
363}
364
365
Lee Thomason1ff38e02012-02-14 18:18:16 -0800366XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
367{
368 if ( firstChild ) {
369 TIXMLASSERT( lastChild );
370 TIXMLASSERT( firstChild->prev == 0 );
371
372 firstChild->prev = addThis;
373 addThis->next = firstChild;
374 firstChild = addThis;
375
Lee Thomason1ff38e02012-02-14 18:18:16 -0800376 addThis->prev = 0;
377 }
378 else {
379 TIXMLASSERT( lastChild == 0 );
380 firstChild = lastChild = addThis;
381
Lee Thomason1ff38e02012-02-14 18:18:16 -0800382 addThis->prev = 0;
383 addThis->next = 0;
384 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800385 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800386 return addThis;
387}
388
389
390XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
391{
392 TIXMLASSERT( afterThis->parent == this );
393 if ( afterThis->parent != this )
394 return 0;
395
396 if ( afterThis->next == 0 ) {
397 // The last node or the only node.
398 return InsertEndChild( addThis );
399 }
400 addThis->prev = afterThis;
401 addThis->next = afterThis->next;
402 afterThis->next->prev = addThis;
403 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800404 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800405 return addThis;
406}
407
408
409
410
Lee Thomason56bdd022012-02-09 18:16:58 -0800411const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800412{
413 for( XMLNode* node=firstChild; node; node=node->next ) {
414 XMLElement* element = node->ToElement();
415 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800416 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800417 return element;
418 }
419 }
420 }
421 return 0;
422}
423
424
Lee Thomason56bdd022012-02-09 18:16:58 -0800425const XMLElement* XMLNode::LastChildElement( const char* value ) const
426{
427 for( XMLNode* node=lastChild; node; node=node->prev ) {
428 XMLElement* element = node->ToElement();
429 if ( element ) {
430 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
431 return element;
432 }
433 }
434 }
435 return 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
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800570void XMLAttribute::SetName( const char* n )
571{
572 name.SetStr( n );
573}
574
575
Lee Thomason1ff38e02012-02-14 18:18:16 -0800576int XMLAttribute::QueryIntAttribute( int* value ) const
577{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800578 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
579 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800580 return WRONG_ATTRIBUTE_TYPE;
581}
582
583
584int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
585{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800586 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
587 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800588 return WRONG_ATTRIBUTE_TYPE;
589}
590
591
592int XMLAttribute::QueryBoolAttribute( bool* value ) const
593{
594 int ival = -1;
595 QueryIntAttribute( &ival );
596
597 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
598 *value = true;
599 return ATTRIBUTE_SUCCESS;
600 }
601 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
602 *value = false;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603 return ATTRIBUTE_SUCCESS;
604 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800605 return WRONG_ATTRIBUTE_TYPE;
606}
607
608
609int XMLAttribute::QueryDoubleAttribute( double* value ) const
610{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800611 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
612 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800613 return WRONG_ATTRIBUTE_TYPE;
614}
615
616
617int XMLAttribute::QueryFloatAttribute( float* value ) const
618{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800619 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
620 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800621 return WRONG_ATTRIBUTE_TYPE;
622}
623
624
625void XMLAttribute::SetAttribute( const char* v )
626{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800627 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800628}
629
630
Lee Thomason1ff38e02012-02-14 18:18:16 -0800631void XMLAttribute::SetAttribute( int v )
632{
633 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800634 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
635 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800636}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800637
638
639void XMLAttribute::SetAttribute( unsigned v )
640{
641 char buf[BUF_SIZE];
642 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
643 value.SetStr( buf );
644}
645
646
647void XMLAttribute::SetAttribute( bool v )
648{
649 char buf[BUF_SIZE];
650 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
651 value.SetStr( buf );
652}
653
654void XMLAttribute::SetAttribute( double v )
655{
656 char buf[BUF_SIZE];
657 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
658 value.SetStr( buf );
659}
660
661void XMLAttribute::SetAttribute( float v )
662{
663 char buf[BUF_SIZE];
664 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
665 value.SetStr( buf );
666}
667
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800668
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800669// --------- XMLElement ---------- //
670XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800671 closing( false ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800672 rootAttribute( 0 )
673 //lastAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674{
675}
676
677
678XMLElement::~XMLElement()
679{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800680 while( rootAttribute ) {
681 XMLAttribute* next = rootAttribute->next;
682 DELETE_ATTRIBUTE( rootAttribute );
683 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800684 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800685}
686
687
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800688XMLAttribute* XMLElement::FindAttribute( const char* name )
689{
690 XMLAttribute* a = 0;
691 for( a=rootAttribute; a; a = a->next ) {
692 if ( XMLUtil::StringEqual( a->Name(), name ) )
693 return a;
694 }
695 return 0;
696}
697
698
699const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
700{
701 XMLAttribute* a = 0;
702 for( a=rootAttribute; a; a = a->next ) {
703 if ( XMLUtil::StringEqual( a->Name(), name ) )
704 return a;
705 }
706 return 0;
707}
708
709
710XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
711{
712 XMLAttribute* attrib = FindAttribute( name );
713 if ( !attrib ) {
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800714 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800715 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800716 LinkAttribute( attrib );
717 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800718 }
719 return attrib;
720}
721
722
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800723void XMLElement::LinkAttribute( XMLAttribute* attrib )
724{
725 if ( rootAttribute ) {
726 XMLAttribute* end = rootAttribute;
727 while ( end->next )
728 end = end->next;
729 end->next = attrib;
730 }
731 else {
732 rootAttribute = attrib;
733 }
734}
735
736
U-Stream\Leeae25a442012-02-17 17:48:16 -0800737void XMLElement::DeleteAttribute( const char* name )
738{
739 XMLAttribute* prev = 0;
740 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
741 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
742 if ( prev ) {
743 prev->next = a->next;
744 }
745 else {
746 rootAttribute = a->next;
747 }
748 DELETE_ATTRIBUTE( a );
749 break;
750 }
751 prev = a;
752 }
753}
754
755
Lee Thomason67d61312012-01-24 16:01:51 -0800756char* XMLElement::ParseAttributes( char* p, bool* closedElement )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800757{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800758 const char* start = p;
Lee Thomason67d61312012-01-24 16:01:51 -0800759 *closedElement = false;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800760
761 // Read the attributes.
762 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800763 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800764 if ( !p || !(*p) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800765 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800766 return 0;
767 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800768
769 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -0800770 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800771 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
772 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -0800773
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800774 p = attrib->ParseDeep( p );
775 if ( !p ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800776 DELETE_ATTRIBUTE( attrib );
Lee Thomasone4422302012-01-20 17:59:50 -0800777 document->SetError( XMLDocument::ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800778 return 0;
779 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800780 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800781 }
Lee Thomasone4422302012-01-20 17:59:50 -0800782 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800783 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800784 if ( closing ) {
785 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
786 return 0;
787 }
Lee Thomason67d61312012-01-24 16:01:51 -0800788 *closedElement = true;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800789 return p+2; // done; sealed element.
790 }
Lee Thomasone4422302012-01-20 17:59:50 -0800791 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792 else if ( *p == '>' ) {
793 ++p;
794 break;
795 }
Lee Thomasone4422302012-01-20 17:59:50 -0800796 else {
797 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
798 return 0;
799 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800800 }
Lee Thomason67d61312012-01-24 16:01:51 -0800801 return p;
802}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800803
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800804
Lee Thomason67d61312012-01-24 16:01:51 -0800805//
806// <ele></ele>
807// <ele>foo<b>bar</b></ele>
808//
809char* XMLElement::ParseDeep( char* p )
810{
811 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800812 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -0800813 if ( !p ) return 0;
814 const char* start = p;
815
816 // The closing element is the </element> form. It is
817 // parsed just like a regular element then deleted from
818 // the DOM.
819 if ( *p == '/' ) {
820 closing = true;
821 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800822 }
Lee Thomason67d61312012-01-24 16:01:51 -0800823
Lee Thomason56bdd022012-02-09 18:16:58 -0800824 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -0800825 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800826
827 bool elementClosed=false;
828 p = ParseAttributes( p, &elementClosed );
829 if ( !p || !*p || elementClosed || closing )
830 return p;
831
832 p = XMLNode::ParseDeep( p );
833 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800834}
835
836
Lee Thomason751da522012-02-10 08:50:51 -0800837bool XMLElement::Accept( XMLVisitor* visitor ) const
838{
839 if ( visitor->VisitEnter( *this, rootAttribute ) )
840 {
841 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
842 {
843 if ( !node->Accept( visitor ) )
844 break;
845 }
846 }
847 return visitor->VisitExit( *this );
848
849}
Lee Thomason56bdd022012-02-09 18:16:58 -0800850
851
Lee Thomason3f57d272012-01-11 15:30:03 -0800852// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -0800853XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -0800854 XMLNode( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -0800855 charBuffer( 0 )
856{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800857 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -0800858}
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800859
860
Lee Thomason3f57d272012-01-11 15:30:03 -0800861XMLDocument::~XMLDocument()
862{
Lee Thomasond1983222012-02-06 08:41:24 -0800863 ClearChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -0800864 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -0800865
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800866#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -0800867 textPool.Trace( "text" );
868 elementPool.Trace( "element" );
869 commentPool.Trace( "comment" );
870 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800871#endif
872
Lee Thomason455c9d42012-02-06 09:14:14 -0800873 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
874 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
875 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
876 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -0800877}
878
879
Lee Thomason18d68bd2012-01-26 18:17:26 -0800880void XMLDocument::InitDocument()
881{
882 errorID = NO_ERROR;
883 errorStr1 = 0;
884 errorStr2 = 0;
885
886 delete [] charBuffer;
887 charBuffer = 0;
888
889}
890
Lee Thomason3f57d272012-01-11 15:30:03 -0800891
Lee Thomason2c85a712012-01-31 08:24:24 -0800892XMLElement* XMLDocument::NewElement( const char* name )
893{
Lee Thomasond1983222012-02-06 08:41:24 -0800894 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
895 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -0800896 ele->SetName( name );
897 return ele;
898}
899
900
Lee Thomason1ff38e02012-02-14 18:18:16 -0800901XMLComment* XMLDocument::NewComment( const char* str )
902{
903 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
904 comment->memPool = &commentPool;
905 comment->SetValue( str );
906 return comment;
907}
908
909
910XMLText* XMLDocument::NewText( const char* str )
911{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800912 XMLText* text = new (textPool.Alloc()) XMLText( this );
913 text->memPool = &textPool;
914 text->SetValue( str );
915 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800916}
917
918
919
Lee Thomason7c913cd2012-01-26 18:32:34 -0800920int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800921{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800922 ClearChildren();
923 InitDocument();
924
925 if ( !p || !*p ) {
926 return true; // correctly parse an empty string?
927 }
928 size_t len = strlen( p );
929 charBuffer = new char[ len+1 ];
930 memcpy( charBuffer, p, len+1 );
Lee Thomason3f57d272012-01-11 15:30:03 -0800931 XMLNode* node = 0;
Lee Thomason85403d82012-01-11 15:55:05 -0800932
Lee Thomason18d68bd2012-01-26 18:17:26 -0800933 char* q = ParseDeep( charBuffer );
Lee Thomason7c913cd2012-01-26 18:32:34 -0800934 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -0800935}
936
937
Lee Thomason5cae8972012-01-24 18:03:07 -0800938void XMLDocument::Print( XMLStreamer* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -0800939{
Lee Thomason5cae8972012-01-24 18:03:07 -0800940 XMLStreamer stdStreamer( stdout );
941 if ( !streamer )
942 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -0800943 //for( XMLNode* node = firstChild; node; node=node->next ) {
944 // node->Print( streamer );
945 //}
946 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -0800947}
948
949
Lee Thomason67d61312012-01-24 16:01:51 -0800950void XMLDocument::SetError( int error, const char* str1, const char* str2 )
951{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800952 errorID = error;
953 printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 ); // fixme: remove
954 errorStr1 = str1;
955 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -0800956}
957
Lee Thomason5cae8972012-01-24 18:03:07 -0800958
Lee Thomason56bdd022012-02-09 18:16:58 -0800959XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false ), textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -0800960{
Lee Thomason857b8682012-01-25 17:50:25 -0800961 for( int i=0; i<ENTITY_RANGE; ++i ) {
962 entityFlag[i] = false;
963 }
964 for( int i=0; i<NUM_ENTITIES; ++i ) {
965 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
966 if ( entities[i].value < ENTITY_RANGE ) {
967 entityFlag[ entities[i].value ] = true;
968 }
969 }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800970 buffer.Push( 0 );
971}
972
973
974void XMLStreamer::Print( const char* format, ... )
975{
976 va_list va;
977 va_start( va, format );
978
979 if ( fp ) {
980 vfprintf( fp, format, va );
981 }
982 else {
983 // This seems brutally complex. Haven't figured out a better
984 // way on windows.
985 #ifdef _MSC_VER
986 int len = -1;
987 while ( len < 0 ) {
988 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
989 if ( len < 0 ) {
990 accumulator.PushArr( 1000 );
991 }
992 }
993 char* p = buffer.PushArr( len ) - 1;
994 memcpy( p, accumulator.Mem(), len+1 );
995 #else
996 int len = vsnprintf( 0, 0, format, va );
997 char* p = buffer.PushArr( len ) - 1;
998 vsprintf_s( p, len+1, format, va );
999 #endif
1000 }
1001 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001002}
1003
1004
1005void XMLStreamer::PrintSpace( int depth )
1006{
1007 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001008 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001009 }
1010}
1011
1012
Lee Thomason951d8832012-01-26 08:47:06 -08001013void XMLStreamer::PrintString( const char* p )
Lee Thomason857b8682012-01-25 17:50:25 -08001014{
Lee Thomason951d8832012-01-26 08:47:06 -08001015 // Look for runs of bytes between entities to print.
1016 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08001017
Lee Thomason951d8832012-01-26 08:47:06 -08001018 while ( *q ) {
1019 if ( *q < ENTITY_RANGE ) {
1020 // Check for entities. If one is found, flush
1021 // the stream up until the entity, write the
1022 // entity, and keep looking.
1023 if ( entityFlag[*q] ) {
1024 while ( p < q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001025 Print( "%c", *p );
Lee Thomason951d8832012-01-26 08:47:06 -08001026 ++p;
1027 }
1028 for( int i=0; i<NUM_ENTITIES; ++i ) {
1029 if ( entities[i].value == *q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001030 Print( "&%s;", entities[i].pattern );
Lee Thomason951d8832012-01-26 08:47:06 -08001031 break;
1032 }
1033 }
1034 ++p;
1035 }
1036 }
1037 ++q;
1038 }
1039 // Flush the remaining string. This will be the entire
1040 // string if an entity wasn't found.
1041 if ( q-p > 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001042 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001043 }
Lee Thomason857b8682012-01-25 17:50:25 -08001044}
1045
U-Stream\Leeae25a442012-02-17 17:48:16 -08001046
Lee Thomason56bdd022012-02-09 18:16:58 -08001047void XMLStreamer::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001048{
1049 if ( elementJustOpened ) {
1050 SealElement();
1051 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001052 stack.Push( name );
1053
1054 if ( textDepth < 0 && depth > 0) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001055 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001056 PrintSpace( depth );
1057 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001058
U-Stream\Leeae25a442012-02-17 17:48:16 -08001059 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001060 elementJustOpened = true;
1061 ++depth;
1062}
1063
1064
1065void XMLStreamer::PushAttribute( const char* name, const char* value )
1066{
1067 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001068 Print( " %s=\"", name );
Lee Thomason18d68bd2012-01-26 18:17:26 -08001069 PrintString( value );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001070 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001071}
1072
1073
1074void XMLStreamer::CloseElement()
1075{
1076 --depth;
1077 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001078
1079 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001080 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001081 }
1082 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001083 if ( textDepth < 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001084 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001085 PrintSpace( depth );
1086 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001087 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001088 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001089
1090 if ( textDepth == depth )
1091 textDepth = -1;
1092 if ( depth == 0 )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001093 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001094 elementJustOpened = false;
1095}
1096
1097
1098void XMLStreamer::SealElement()
1099{
1100 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001101 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001102}
1103
1104
Lee Thomason50f97b22012-02-11 16:33:40 -08001105void XMLStreamer::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001106{
Lee Thomason56bdd022012-02-09 18:16:58 -08001107 textDepth = depth-1;
1108
Lee Thomason5cae8972012-01-24 18:03:07 -08001109 if ( elementJustOpened ) {
1110 SealElement();
1111 }
Lee Thomason50f97b22012-02-11 16:33:40 -08001112 if ( cdata )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001113 Print( "<![CDATA[" );
Lee Thomason951d8832012-01-26 08:47:06 -08001114 PrintString( text );
Lee Thomason50f97b22012-02-11 16:33:40 -08001115 if ( cdata )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001116 Print( "]]>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001117}
1118
1119
1120void XMLStreamer::PushComment( const char* comment )
1121{
1122 if ( elementJustOpened ) {
1123 SealElement();
1124 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001125 if ( textDepth < 0 && depth > 0) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001126 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001127 PrintSpace( depth );
1128 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001129 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001130}
Lee Thomason751da522012-02-10 08:50:51 -08001131
1132
1133bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
1134{
1135 OpenElement( element.Name() );
1136 while ( attribute ) {
1137 PushAttribute( attribute->Name(), attribute->Value() );
1138 attribute = attribute->Next();
1139 }
1140 return true;
1141}
1142
1143
1144bool XMLStreamer::VisitExit( const XMLElement& element )
1145{
1146 CloseElement();
1147 return true;
1148}
1149
1150
1151bool XMLStreamer::Visit( const XMLText& text )
1152{
1153 PushText( text.Value() );
1154 return true;
1155}
1156
1157
1158bool XMLStreamer::Visit( const XMLComment& comment )
1159{
1160 PushComment( comment.Value() );
1161 return true;
1162}