blob: 740f1f5b90e1db13d471357e27695ec83e29b8ad [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 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080085 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
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: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800201 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800202 // - Everthing else is unknown to tinyxml.
203 //
204
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800205 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800206 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
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800211 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800212 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 Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800247 else {
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
253 *node = returnNode;
254 return p;
255}
256
257
Lee Thomason751da522012-02-10 08:50:51 -0800258bool XMLDocument::Accept( XMLVisitor* visitor ) const
259{
260 if ( visitor->VisitEnter( *this ) )
261 {
262 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
263 {
264 if ( !node->Accept( visitor ) )
265 break;
266 }
267 }
268 return visitor->VisitExit( *this );
269}
Lee Thomason56bdd022012-02-09 18:16:58 -0800270
271
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800272// --------- XMLNode ----------- //
273
274XMLNode::XMLNode( XMLDocument* doc ) :
275 document( doc ),
276 parent( 0 ),
277 firstChild( 0 ), lastChild( 0 ),
278 prev( 0 ), next( 0 )
279{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800280}
281
282
283XMLNode::~XMLNode()
284{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800285 ClearChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800286 if ( parent ) {
287 parent->Unlink( this );
288 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800289}
290
291
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800292void XMLNode::SetValue( const char* str, bool staticMem )
293{
294 if ( staticMem )
295 value.SetInternedStr( str );
296 else
297 value.SetStr( str );
298}
299
300
Lee Thomason18d68bd2012-01-26 18:17:26 -0800301void XMLNode::ClearChildren()
302{
Lee Thomasond923c672012-01-23 08:44:25 -0800303 while( firstChild ) {
304 XMLNode* node = firstChild;
305 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800306
Lee Thomason43f59302012-02-06 18:18:11 -0800307 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800308 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800309 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800310}
311
312
313void XMLNode::Unlink( XMLNode* child )
314{
315 TIXMLASSERT( child->parent == this );
316 if ( child == firstChild )
317 firstChild = firstChild->next;
318 if ( child == lastChild )
319 lastChild = lastChild->prev;
320
321 if ( child->prev ) {
322 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800323 }
Lee Thomasond923c672012-01-23 08:44:25 -0800324 if ( child->next ) {
325 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800326 }
Lee Thomasond923c672012-01-23 08:44:25 -0800327 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800328}
329
330
U-Stream\Leeae25a442012-02-17 17:48:16 -0800331void XMLNode::DeleteChild( XMLNode* node )
332{
333 TIXMLASSERT( node->parent == this );
334 DELETE_NODE( node );
335}
336
337
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800338XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
339{
340 if ( lastChild ) {
341 TIXMLASSERT( firstChild );
342 TIXMLASSERT( lastChild->next == 0 );
343 lastChild->next = addThis;
344 addThis->prev = lastChild;
345 lastChild = addThis;
346
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800347 addThis->next = 0;
348 }
349 else {
350 TIXMLASSERT( firstChild == 0 );
351 firstChild = lastChild = addThis;
352
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800353 addThis->prev = 0;
354 addThis->next = 0;
355 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800356 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800357 return addThis;
358}
359
360
Lee Thomason1ff38e02012-02-14 18:18:16 -0800361XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
362{
363 if ( firstChild ) {
364 TIXMLASSERT( lastChild );
365 TIXMLASSERT( firstChild->prev == 0 );
366
367 firstChild->prev = addThis;
368 addThis->next = firstChild;
369 firstChild = addThis;
370
Lee Thomason1ff38e02012-02-14 18:18:16 -0800371 addThis->prev = 0;
372 }
373 else {
374 TIXMLASSERT( lastChild == 0 );
375 firstChild = lastChild = addThis;
376
Lee Thomason1ff38e02012-02-14 18:18:16 -0800377 addThis->prev = 0;
378 addThis->next = 0;
379 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800380 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800381 return addThis;
382}
383
384
385XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
386{
387 TIXMLASSERT( afterThis->parent == this );
388 if ( afterThis->parent != this )
389 return 0;
390
391 if ( afterThis->next == 0 ) {
392 // The last node or the only node.
393 return InsertEndChild( addThis );
394 }
395 addThis->prev = afterThis;
396 addThis->next = afterThis->next;
397 afterThis->next->prev = addThis;
398 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800399 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800400 return addThis;
401}
402
403
404
405
Lee Thomason56bdd022012-02-09 18:16:58 -0800406const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800407{
408 for( XMLNode* node=firstChild; node; node=node->next ) {
409 XMLElement* element = node->ToElement();
410 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800411 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800412 return element;
413 }
414 }
415 }
416 return 0;
417}
418
419
Lee Thomason56bdd022012-02-09 18:16:58 -0800420const XMLElement* XMLNode::LastChildElement( const char* value ) const
421{
422 for( XMLNode* node=lastChild; node; node=node->prev ) {
423 XMLElement* element = node->ToElement();
424 if ( element ) {
425 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
426 return element;
427 }
428 }
429 }
430 return 0;
431}
432
433
Lee Thomason67d61312012-01-24 16:01:51 -0800434char* XMLNode::ParseDeep( char* p )
435{
436 while( p && *p ) {
437 XMLNode* node = 0;
Lee Thomasond1983222012-02-06 08:41:24 -0800438 p = document->Identify( p, &node );
Lee Thomason67d61312012-01-24 16:01:51 -0800439 if ( p && node ) {
440 p = node->ParseDeep( p );
441 // FIXME: is it the correct closing element?
442 if ( node->IsClosingElement() ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800443 DELETE_NODE( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800444 return p;
445 }
446 this->InsertEndChild( node );
447 }
448 }
449 return 0;
450}
451
Lee Thomason5492a1c2012-01-23 15:32:10 -0800452// --------- XMLText ---------- //
453char* XMLText::ParseDeep( char* p )
454{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800455 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800456 if ( this->CData() ) {
457 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800458 if ( !p ) {
459 document->SetError( XMLDocument::ERROR_PARSING_CDATA, start, 0 );
460 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800461 return p;
462 }
463 else {
464 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800465 if ( !p ) {
466 document->SetError( XMLDocument::ERROR_PARSING_TEXT, start, 0 );
467 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800468 if ( p && *p ) {
469 return p-1;
470 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800471 }
472 return 0;
473}
474
475
Lee Thomason56bdd022012-02-09 18:16:58 -0800476bool XMLText::Accept( XMLVisitor* visitor ) const
477{
478 return visitor->Visit( *this );
479}
480
481
Lee Thomason3f57d272012-01-11 15:30:03 -0800482// --------- XMLComment ---------- //
483
Lee Thomasone4422302012-01-20 17:59:50 -0800484XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800485{
486}
487
488
Lee Thomasonce0763e2012-01-11 15:43:54 -0800489XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800490{
Lee Thomasond923c672012-01-23 08:44:25 -0800491 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800492}
493
494
Lee Thomasonce0763e2012-01-11 15:43:54 -0800495char* XMLComment::ParseDeep( char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800496{
497 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800498 const char* start = p;
499 p = value.ParseText( p, "-->", StrPair::COMMENT );
500 if ( p == 0 ) {
501 document->SetError( XMLDocument::ERROR_PARSING_COMMENT, start, 0 );
502 }
503 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800504}
505
506
Lee Thomason751da522012-02-10 08:50:51 -0800507bool XMLComment::Accept( XMLVisitor* visitor ) const
508{
509 return visitor->Visit( *this );
510}
Lee Thomason56bdd022012-02-09 18:16:58 -0800511
512
Lee Thomason50f97b22012-02-11 16:33:40 -0800513// --------- XMLDeclaration ---------- //
514
515XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
516{
517}
518
519
520XMLDeclaration::~XMLDeclaration()
521{
522 //printf( "~XMLDeclaration\n" );
523}
524
525
526char* XMLDeclaration::ParseDeep( char* p )
527{
528 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800529 const char* start = p;
530 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
531 if ( p == 0 ) {
532 document->SetError( XMLDocument::ERROR_PARSING_DECLARATION, start, 0 );
533 }
534 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800535}
536
537
538bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
539{
540 return visitor->Visit( *this );
541}
542
543// --------- XMLUnknown ---------- //
544
545XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
546{
547}
548
549
550XMLUnknown::~XMLUnknown()
551{
552}
553
554
555char* XMLUnknown::ParseDeep( char* p )
556{
557 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800558 const char* start = p;
559
560 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
561 if ( !p ) {
562 document->SetError( XMLDocument::ERROR_PARSING_UNKNOWN, start, 0 );
563 }
564 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800565}
566
567
568bool XMLUnknown::Accept( XMLVisitor* visitor ) const
569{
570 return visitor->Visit( *this );
571}
572
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573// --------- XMLAttribute ---------- //
574char* XMLAttribute::ParseDeep( char* p )
575{
Lee Thomason56bdd022012-02-09 18:16:58 -0800576 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800577 if ( !p || !*p ) return 0;
578
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579 char endTag[2] = { *p, 0 };
580 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800581 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomasone4422302012-01-20 17:59:50 -0800582 if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800583 return p;
584}
585
586
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800587void XMLAttribute::SetName( const char* n )
588{
589 name.SetStr( n );
590}
591
592
Lee Thomason1ff38e02012-02-14 18:18:16 -0800593int XMLAttribute::QueryIntAttribute( int* value ) const
594{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800595 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
596 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800597 return WRONG_ATTRIBUTE_TYPE;
598}
599
600
601int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
602{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
604 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800605 return WRONG_ATTRIBUTE_TYPE;
606}
607
608
609int XMLAttribute::QueryBoolAttribute( bool* value ) const
610{
611 int ival = -1;
612 QueryIntAttribute( &ival );
613
614 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
615 *value = true;
616 return ATTRIBUTE_SUCCESS;
617 }
618 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
619 *value = false;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620 return ATTRIBUTE_SUCCESS;
621 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800622 return WRONG_ATTRIBUTE_TYPE;
623}
624
625
626int XMLAttribute::QueryDoubleAttribute( double* value ) const
627{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800628 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
629 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800630 return WRONG_ATTRIBUTE_TYPE;
631}
632
633
634int XMLAttribute::QueryFloatAttribute( float* value ) const
635{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800636 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
637 return ATTRIBUTE_SUCCESS;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800638 return WRONG_ATTRIBUTE_TYPE;
639}
640
641
642void XMLAttribute::SetAttribute( const char* v )
643{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800644 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800645}
646
647
Lee Thomason1ff38e02012-02-14 18:18:16 -0800648void XMLAttribute::SetAttribute( int v )
649{
650 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800651 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
652 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800653}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800654
655
656void XMLAttribute::SetAttribute( unsigned v )
657{
658 char buf[BUF_SIZE];
659 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
660 value.SetStr( buf );
661}
662
663
664void XMLAttribute::SetAttribute( bool v )
665{
666 char buf[BUF_SIZE];
667 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
668 value.SetStr( buf );
669}
670
671void XMLAttribute::SetAttribute( double v )
672{
673 char buf[BUF_SIZE];
674 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
675 value.SetStr( buf );
676}
677
678void XMLAttribute::SetAttribute( float v )
679{
680 char buf[BUF_SIZE];
681 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
682 value.SetStr( buf );
683}
684
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800685
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686// --------- XMLElement ---------- //
687XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800688 closing( false ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800689 rootAttribute( 0 )
690 //lastAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800691{
692}
693
694
695XMLElement::~XMLElement()
696{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800697 while( rootAttribute ) {
698 XMLAttribute* next = rootAttribute->next;
699 DELETE_ATTRIBUTE( rootAttribute );
700 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702}
703
704
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800705XMLAttribute* XMLElement::FindAttribute( const char* name )
706{
707 XMLAttribute* a = 0;
708 for( a=rootAttribute; a; a = a->next ) {
709 if ( XMLUtil::StringEqual( a->Name(), name ) )
710 return a;
711 }
712 return 0;
713}
714
715
716const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
717{
718 XMLAttribute* a = 0;
719 for( a=rootAttribute; a; a = a->next ) {
720 if ( XMLUtil::StringEqual( a->Name(), name ) )
721 return a;
722 }
723 return 0;
724}
725
726
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800727const char* XMLElement::GetText() const
728{
729 if ( FirstChild() && FirstChild()->ToText() ) {
730 return FirstChild()->ToText()->Value();
731 }
732 return 0;
733}
734
735
736
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800737XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
738{
739 XMLAttribute* attrib = FindAttribute( name );
740 if ( !attrib ) {
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800741 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800742 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800743 LinkAttribute( attrib );
744 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800745 }
746 return attrib;
747}
748
749
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800750void XMLElement::LinkAttribute( XMLAttribute* attrib )
751{
752 if ( rootAttribute ) {
753 XMLAttribute* end = rootAttribute;
754 while ( end->next )
755 end = end->next;
756 end->next = attrib;
757 }
758 else {
759 rootAttribute = attrib;
760 }
761}
762
763
U-Stream\Leeae25a442012-02-17 17:48:16 -0800764void XMLElement::DeleteAttribute( const char* name )
765{
766 XMLAttribute* prev = 0;
767 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
768 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
769 if ( prev ) {
770 prev->next = a->next;
771 }
772 else {
773 rootAttribute = a->next;
774 }
775 DELETE_ATTRIBUTE( a );
776 break;
777 }
778 prev = a;
779 }
780}
781
782
Lee Thomason67d61312012-01-24 16:01:51 -0800783char* XMLElement::ParseAttributes( char* p, bool* closedElement )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800784{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800785 const char* start = p;
Lee Thomason67d61312012-01-24 16:01:51 -0800786 *closedElement = false;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800787
788 // Read the attributes.
789 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800790 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800791 if ( !p || !(*p) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800792 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800793 return 0;
794 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800795
796 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -0800797 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800798 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
799 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -0800800
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801 p = attrib->ParseDeep( p );
802 if ( !p ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800803 DELETE_ATTRIBUTE( attrib );
Lee Thomasone4422302012-01-20 17:59:50 -0800804 document->SetError( XMLDocument::ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805 return 0;
806 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800807 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800808 }
Lee Thomasone4422302012-01-20 17:59:50 -0800809 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800810 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800811 if ( closing ) {
812 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
813 return 0;
814 }
Lee Thomason67d61312012-01-24 16:01:51 -0800815 *closedElement = true;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800816 return p+2; // done; sealed element.
817 }
Lee Thomasone4422302012-01-20 17:59:50 -0800818 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800819 else if ( *p == '>' ) {
820 ++p;
821 break;
822 }
Lee Thomasone4422302012-01-20 17:59:50 -0800823 else {
824 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
825 return 0;
826 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800827 }
Lee Thomason67d61312012-01-24 16:01:51 -0800828 return p;
829}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800830
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800831
Lee Thomason67d61312012-01-24 16:01:51 -0800832//
833// <ele></ele>
834// <ele>foo<b>bar</b></ele>
835//
836char* XMLElement::ParseDeep( char* p )
837{
838 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -0800839 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -0800840 if ( !p ) return 0;
841 const char* start = p;
842
843 // The closing element is the </element> form. It is
844 // parsed just like a regular element then deleted from
845 // the DOM.
846 if ( *p == '/' ) {
847 closing = true;
848 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800849 }
Lee Thomason67d61312012-01-24 16:01:51 -0800850
Lee Thomason56bdd022012-02-09 18:16:58 -0800851 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -0800852 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800853
854 bool elementClosed=false;
855 p = ParseAttributes( p, &elementClosed );
856 if ( !p || !*p || elementClosed || closing )
857 return p;
858
859 p = XMLNode::ParseDeep( p );
860 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800861}
862
863
Lee Thomason751da522012-02-10 08:50:51 -0800864bool XMLElement::Accept( XMLVisitor* visitor ) const
865{
866 if ( visitor->VisitEnter( *this, rootAttribute ) )
867 {
868 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
869 {
870 if ( !node->Accept( visitor ) )
871 break;
872 }
873 }
874 return visitor->VisitExit( *this );
875
876}
Lee Thomason56bdd022012-02-09 18:16:58 -0800877
878
Lee Thomason3f57d272012-01-11 15:30:03 -0800879// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -0800880XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -0800881 XMLNode( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -0800882 charBuffer( 0 )
883{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800884 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -0800885}
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800886
887
Lee Thomason3f57d272012-01-11 15:30:03 -0800888XMLDocument::~XMLDocument()
889{
Lee Thomasond1983222012-02-06 08:41:24 -0800890 ClearChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -0800891 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -0800892
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800893#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -0800894 textPool.Trace( "text" );
895 elementPool.Trace( "element" );
896 commentPool.Trace( "comment" );
897 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800898#endif
899
Lee Thomason455c9d42012-02-06 09:14:14 -0800900 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
901 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
902 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
903 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -0800904}
905
906
Lee Thomason18d68bd2012-01-26 18:17:26 -0800907void XMLDocument::InitDocument()
908{
909 errorID = NO_ERROR;
910 errorStr1 = 0;
911 errorStr2 = 0;
912
913 delete [] charBuffer;
914 charBuffer = 0;
915
916}
917
Lee Thomason3f57d272012-01-11 15:30:03 -0800918
Lee Thomason2c85a712012-01-31 08:24:24 -0800919XMLElement* XMLDocument::NewElement( const char* name )
920{
Lee Thomasond1983222012-02-06 08:41:24 -0800921 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
922 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -0800923 ele->SetName( name );
924 return ele;
925}
926
927
Lee Thomason1ff38e02012-02-14 18:18:16 -0800928XMLComment* XMLDocument::NewComment( const char* str )
929{
930 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
931 comment->memPool = &commentPool;
932 comment->SetValue( str );
933 return comment;
934}
935
936
937XMLText* XMLDocument::NewText( const char* str )
938{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800939 XMLText* text = new (textPool.Alloc()) XMLText( this );
940 text->memPool = &textPool;
941 text->SetValue( str );
942 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800943}
944
945
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800946int XMLDocument::Load( const char* filename )
947{
948 ClearChildren();
949 InitDocument();
950
951 FILE* fp = fopen( filename, "rb" );
952 if ( !fp ) {
953 SetError( ERROR_FILE_NOT_FOUND, filename, 0 );
954 return errorID;
955 }
956 Load( fp );
957 fclose( fp );
958 return errorID;
959}
960
961
962int XMLDocument::Load( FILE* fp )
963{
964 ClearChildren();
965 InitDocument();
966
967 fseek( fp, 0, SEEK_END );
968 unsigned size = ftell( fp );
969 fseek( fp, 0, SEEK_SET );
970
971 charBuffer = new char[size+1];
972 fread( charBuffer, size, 1, fp );
973 charBuffer[size] = 0;
974
975 ParseDeep( charBuffer );
976 return errorID;
977}
978
979
980void XMLDocument::Save( const char* filename )
981{
982 FILE* fp = fopen( filename, "w" );
983 XMLStreamer stream( fp );
984 Print( &stream );
985 fclose( fp );
986}
987
Lee Thomason1ff38e02012-02-14 18:18:16 -0800988
Lee Thomason7c913cd2012-01-26 18:32:34 -0800989int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800990{
Lee Thomason18d68bd2012-01-26 18:17:26 -0800991 ClearChildren();
992 InitDocument();
993
994 if ( !p || !*p ) {
995 return true; // correctly parse an empty string?
996 }
997 size_t len = strlen( p );
998 charBuffer = new char[ len+1 ];
999 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001000
1001 ParseDeep( charBuffer );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001002 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001003}
1004
1005
Lee Thomason5cae8972012-01-24 18:03:07 -08001006void XMLDocument::Print( XMLStreamer* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001007{
Lee Thomason5cae8972012-01-24 18:03:07 -08001008 XMLStreamer stdStreamer( stdout );
1009 if ( !streamer )
1010 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001011 //for( XMLNode* node = firstChild; node; node=node->next ) {
1012 // node->Print( streamer );
1013 //}
1014 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001015}
1016
1017
Lee Thomason67d61312012-01-24 16:01:51 -08001018void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1019{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001020 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001021 errorStr1 = str1;
1022 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001023}
1024
Lee Thomason5cae8972012-01-24 18:03:07 -08001025
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001026void XMLDocument::PrintError() const
1027{
1028 if ( errorID ) {
1029 char buf1[20] = { 0 };
1030 char buf2[20] = { 0 };
1031
1032 if ( errorStr1 ) {
1033 strncpy( buf1, errorStr1, 20 );
1034 buf1[19] = 0;
1035 }
1036 if ( errorStr2 ) {
1037 strncpy( buf2, errorStr2, 20 );
1038 buf2[19] = 0;
1039 }
1040
1041 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1042 errorID, buf1, buf2 );
1043 }
1044}
1045
1046
1047XMLStreamer::XMLStreamer( FILE* file ) :
1048 elementJustOpened( false ),
1049 firstElement( true ),
1050 fp( file ),
1051 depth( 0 ),
1052 textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -08001053{
Lee Thomason857b8682012-01-25 17:50:25 -08001054 for( int i=0; i<ENTITY_RANGE; ++i ) {
1055 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001056 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001057 }
1058 for( int i=0; i<NUM_ENTITIES; ++i ) {
1059 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1060 if ( entities[i].value < ENTITY_RANGE ) {
1061 entityFlag[ entities[i].value ] = true;
1062 }
1063 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001064 restrictedEntityFlag['&'] = true;
1065 restrictedEntityFlag['<'] = true;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001066 buffer.Push( 0 );
1067}
1068
1069
1070void XMLStreamer::Print( const char* format, ... )
1071{
1072 va_list va;
1073 va_start( va, format );
1074
1075 if ( fp ) {
1076 vfprintf( fp, format, va );
1077 }
1078 else {
1079 // This seems brutally complex. Haven't figured out a better
1080 // way on windows.
1081 #ifdef _MSC_VER
1082 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001083 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001084 while ( len < 0 ) {
1085 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
1086 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001087 accumulator.PushArr( expand );
1088 expand *= 3/2;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001089 }
1090 }
1091 char* p = buffer.PushArr( len ) - 1;
1092 memcpy( p, accumulator.Mem(), len+1 );
1093 #else
1094 int len = vsnprintf( 0, 0, format, va );
1095 char* p = buffer.PushArr( len ) - 1;
1096 vsprintf_s( p, len+1, format, va );
1097 #endif
1098 }
1099 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001100}
1101
1102
1103void XMLStreamer::PrintSpace( int depth )
1104{
1105 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001106 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001107 }
1108}
1109
1110
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001111void XMLStreamer::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001112{
Lee Thomason951d8832012-01-26 08:47:06 -08001113 // Look for runs of bytes between entities to print.
1114 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001115 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001116
Lee Thomason951d8832012-01-26 08:47:06 -08001117 while ( *q ) {
1118 if ( *q < ENTITY_RANGE ) {
1119 // Check for entities. If one is found, flush
1120 // the stream up until the entity, write the
1121 // entity, and keep looking.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001122 if ( flag[*q] ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001123 while ( p < q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001124 Print( "%c", *p );
Lee Thomason951d8832012-01-26 08:47:06 -08001125 ++p;
1126 }
1127 for( int i=0; i<NUM_ENTITIES; ++i ) {
1128 if ( entities[i].value == *q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001129 Print( "&%s;", entities[i].pattern );
Lee Thomason951d8832012-01-26 08:47:06 -08001130 break;
1131 }
1132 }
1133 ++p;
1134 }
1135 }
1136 ++q;
1137 }
1138 // Flush the remaining string. This will be the entire
1139 // string if an entity wasn't found.
1140 if ( q-p > 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001141 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001142 }
Lee Thomason857b8682012-01-25 17:50:25 -08001143}
1144
U-Stream\Leeae25a442012-02-17 17:48:16 -08001145
Lee Thomason56bdd022012-02-09 18:16:58 -08001146void XMLStreamer::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001147{
1148 if ( elementJustOpened ) {
1149 SealElement();
1150 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001151 stack.Push( name );
1152
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001153 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001154 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001155 PrintSpace( depth );
1156 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001157
U-Stream\Leeae25a442012-02-17 17:48:16 -08001158 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001159 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001160 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001161 ++depth;
1162}
1163
1164
1165void XMLStreamer::PushAttribute( const char* name, const char* value )
1166{
1167 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001168 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001169 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001170 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001171}
1172
1173
1174void XMLStreamer::CloseElement()
1175{
1176 --depth;
1177 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001178
1179 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001180 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001181 }
1182 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001183 if ( textDepth < 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001184 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001185 PrintSpace( depth );
1186 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001187 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001188 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001189
1190 if ( textDepth == depth )
1191 textDepth = -1;
1192 if ( depth == 0 )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001193 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001194 elementJustOpened = false;
1195}
1196
1197
1198void XMLStreamer::SealElement()
1199{
1200 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001201 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001202}
1203
1204
Lee Thomason50f97b22012-02-11 16:33:40 -08001205void XMLStreamer::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001206{
Lee Thomason56bdd022012-02-09 18:16:58 -08001207 textDepth = depth-1;
1208
Lee Thomason5cae8972012-01-24 18:03:07 -08001209 if ( elementJustOpened ) {
1210 SealElement();
1211 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001212 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001213 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001214 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001215 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001216 }
1217 else {
1218 PrintString( text, true );
1219 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001220}
1221
1222
1223void XMLStreamer::PushComment( const char* comment )
1224{
1225 if ( elementJustOpened ) {
1226 SealElement();
1227 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001228 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001229 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001230 PrintSpace( depth );
1231 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001232 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001233 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001234}
Lee Thomason751da522012-02-10 08:50:51 -08001235
1236
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001237void XMLStreamer::PushDeclaration( const char* value )
1238{
1239 if ( elementJustOpened ) {
1240 SealElement();
1241 }
1242 if ( textDepth < 0 && !firstElement) {
1243 Print( "\n" );
1244 PrintSpace( depth );
1245 }
1246 firstElement = false;
1247 Print( "<?%s?>", value );
1248}
1249
1250
1251void XMLStreamer::PushUnknown( const char* value )
1252{
1253 if ( elementJustOpened ) {
1254 SealElement();
1255 }
1256 if ( textDepth < 0 && !firstElement ) {
1257 Print( "\n" );
1258 PrintSpace( depth );
1259 }
1260 firstElement = false;
1261 Print( "<!%s>", value );
1262}
1263
1264
Lee Thomason751da522012-02-10 08:50:51 -08001265bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
1266{
1267 OpenElement( element.Name() );
1268 while ( attribute ) {
1269 PushAttribute( attribute->Name(), attribute->Value() );
1270 attribute = attribute->Next();
1271 }
1272 return true;
1273}
1274
1275
1276bool XMLStreamer::VisitExit( const XMLElement& element )
1277{
1278 CloseElement();
1279 return true;
1280}
1281
1282
1283bool XMLStreamer::Visit( const XMLText& text )
1284{
1285 PushText( text.Value() );
1286 return true;
1287}
1288
1289
1290bool XMLStreamer::Visit( const XMLComment& comment )
1291{
1292 PushComment( comment.Value() );
1293 return true;
1294}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001295
1296bool XMLStreamer::Visit( const XMLDeclaration& declaration )
1297{
1298 PushDeclaration( declaration.Value() );
1299 return true;
1300}
1301
1302
1303bool XMLStreamer::Visit( const XMLUnknown& unknown )
1304{
1305 PushUnknown( unknown.Value() );
1306 return true;
1307}
1308
1309