blob: a8a7be3c8fe2749480009c04634067d1e117921a [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>
U-Lama\Lee560bd472011-12-28 19:42:49 -08007
8using namespace tinyxml2;
9
Lee Thomasone4422302012-01-20 17:59:50 -080010static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080011static const char LF = LINE_FEED;
12static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
13static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080014static const char SINGLE_QUOTE = '\'';
15static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080016
Lee Thomason8ee79892012-01-25 17:44:30 -080017struct Entity {
18 const char* pattern;
19 int length;
20 char value;
21};
22
23static const int NUM_ENTITIES = 5;
24static const Entity entities[NUM_ENTITIES] =
25{
26 { "quot", 4, '\"' },
27 { "amp", 3, '&' },
28 { "apos", 4, '\'' },
29 { "lt", 2, '<' },
30 { "gt", 2, '>' }
31};
32
Lee Thomasonfde6a752012-01-14 18:08:12 -080033
Lee Thomason3f57d272012-01-11 15:30:03 -080034// --------- CharBuffer ----------- //
U-Lama\Lee560bd472011-12-28 19:42:49 -080035/*static*/ CharBuffer* CharBuffer::Construct( const char* in )
36{
37 size_t len = strlen( in );
38 size_t size = len + sizeof( CharBuffer );
39 CharBuffer* cb = (CharBuffer*) malloc( size );
40 cb->length = len;
41 strcpy( cb->mem, in );
42 return cb;
43}
44
45
46/*static*/ void CharBuffer::Free( CharBuffer* cb )
47{
48 free( cb );
49}
50
51
Lee Thomasone4422302012-01-20 17:59:50 -080052const char* StrPair::GetStr()
53{
54 if ( flags & NEEDS_FLUSH ) {
55 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -080056 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -080057
Lee Thomason8ee79892012-01-25 17:44:30 -080058 if ( flags ) {
Lee Thomasone4422302012-01-20 17:59:50 -080059 char* p = start;
60 char* q = start;
61
62 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -080063 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -080064 // CR-LF pair becomes LF
65 // CR alone becomes LF
66 // LF-CR becomes LF
67 if ( *(p+1) == LF ) {
68 p += 2;
69 }
70 else {
71 ++p;
72 }
73 *q = LF;
74 }
Lee Thomason8ee79892012-01-25 17:44:30 -080075 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -080076 if ( *(p+1) == CR ) {
77 p += 2;
78 }
79 else {
80 ++p;
81 }
82 *q = LF;
83 }
Lee Thomason8ee79892012-01-25 17:44:30 -080084 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
85 int i=0;
86 for( i=0; i<NUM_ENTITIES; ++i ) {
87 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
88 && *(p+entities[i].length+1) == ';' )
89 {
90 // Found an entity convert;
91 *q = entities[i].value;
92 ++q;
93 p += entities[i].length + 2;
94 break;
95 }
96 }
97 if ( i == NUM_ENTITIES ) {
98 // fixme: treat as error?
99 ++p;
100 ++q;
101 }
102 }
Lee Thomasone4422302012-01-20 17:59:50 -0800103 else {
104 *q = *p;
105 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800106 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800107 }
108 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800109 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800110 }
111 flags = 0;
112 }
113 return start;
114}
115
116
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800117// --------- XMLBase ----------- //
Lee Thomasone4422302012-01-20 17:59:50 -0800118char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag )
Lee Thomason3f57d272012-01-11 15:30:03 -0800119{
120 TIXMLASSERT( endTag && *endTag );
121
Lee Thomasonfde6a752012-01-14 18:08:12 -0800122 char* start = p;
Lee Thomasonfde6a752012-01-14 18:08:12 -0800123 char endChar = *endTag;
124 int length = strlen( endTag );
Lee Thomason3f57d272012-01-11 15:30:03 -0800125
Lee Thomasonfde6a752012-01-14 18:08:12 -0800126 // Inner loop of text parsing.
Lee Thomason3f57d272012-01-11 15:30:03 -0800127 while ( *p ) {
Lee Thomasonfde6a752012-01-14 18:08:12 -0800128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800129 pair->Set( start, p, StrPair::NEEDS_ENTITY_PROCESSING | StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasonec975ce2012-01-23 11:42:06 -0800130 return p + length;
Lee Thomason3f57d272012-01-11 15:30:03 -0800131 }
Lee Thomasonec975ce2012-01-23 11:42:06 -0800132 ++p;
Lee Thomason3f57d272012-01-11 15:30:03 -0800133 }
Lee Thomasone4422302012-01-20 17:59:50 -0800134 return p;
Lee Thomason3f57d272012-01-11 15:30:03 -0800135}
136
137
Lee Thomasond34f52c2012-01-20 12:55:24 -0800138char* XMLBase::ParseName( char* p, StrPair* pair )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800139{
140 char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800141
142 start = p;
143 if ( !start || !(*start) ) {
144 return 0;
145 }
146
147 if ( !IsAlpha( *p ) ) {
148 return 0;
149 }
150
151 while( *p && (
152 IsAlphaNum( (unsigned char) *p )
153 || *p == '_'
154 || *p == '-'
155 || *p == '.'
156 || *p == ':' ))
157 {
158 ++p;
159 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800160
161 if ( p > start ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800162 pair->Set( start, p, 0 );
163 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800164 }
Lee Thomason39ede242012-01-20 11:27:56 -0800165 return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800166}
167
168
169char* XMLBase::Identify( XMLDocument* document, char* p, XMLNode** node )
170{
171 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800172 char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800173 p = XMLNode::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800174 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800175 {
176 return 0;
177 }
178
179 // What is this thing?
180 // - Elements start with a letter or underscore, but xml is reserved.
181 // - Comments: <!--
182 // - Decleration: <?xml
183 // - Everthing else is unknown to tinyxml.
184 //
185
186 static const char* xmlHeader = { "<?xml" };
187 static const char* commentHeader = { "<!--" };
188 static const char* dtdHeader = { "<!" };
189 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800190 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800191
192 static const int xmlHeaderLen = 5;
193 static const int commentHeaderLen = 4;
194 static const int dtdHeaderLen = 2;
195 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800196 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800197
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800198 if ( StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800199 returnNode = new XMLComment( document );
200 p += commentHeaderLen;
201 }
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800202 else if ( StringEqual( p, elementHeader, elementHeaderLen ) ) {
203 returnNode = new XMLElement( document );
204 p += elementHeaderLen;
205 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800206 // fixme: better text detection
207 else if ( (*p != '<') && IsAlphaNum( *p ) ) {
208 // fixme: this is filtering out empty text...should it?
209 returnNode = new XMLText( document );
210 p = start; // Back it up, all the text counts.
211 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800212 else {
213 TIXMLASSERT( 0 );
214 }
215
216 *node = returnNode;
217 return p;
218}
219
220
221// --------- XMLNode ----------- //
222
223XMLNode::XMLNode( XMLDocument* doc ) :
224 document( doc ),
225 parent( 0 ),
Lee Thomason67d61312012-01-24 16:01:51 -0800226 isTextParent( false ),
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800227 firstChild( 0 ), lastChild( 0 ),
228 prev( 0 ), next( 0 )
229{
230
231}
232
233
234XMLNode::~XMLNode()
235{
Lee Thomasond923c672012-01-23 08:44:25 -0800236 //printf( "~XMLNode %x\n", this );
237 while( firstChild ) {
238 XMLNode* node = firstChild;
239 Unlink( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800240 delete node;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800241 }
Lee Thomasond923c672012-01-23 08:44:25 -0800242}
243
244
245void XMLNode::Unlink( XMLNode* child )
246{
247 TIXMLASSERT( child->parent == this );
248 if ( child == firstChild )
249 firstChild = firstChild->next;
250 if ( child == lastChild )
251 lastChild = lastChild->prev;
252
253 if ( child->prev ) {
254 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800255 }
Lee Thomasond923c672012-01-23 08:44:25 -0800256 if ( child->next ) {
257 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800258 }
Lee Thomasond923c672012-01-23 08:44:25 -0800259 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800260}
261
262
263XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
264{
265 if ( lastChild ) {
266 TIXMLASSERT( firstChild );
267 TIXMLASSERT( lastChild->next == 0 );
268 lastChild->next = addThis;
269 addThis->prev = lastChild;
270 lastChild = addThis;
271
272 addThis->parent = this;
273 addThis->next = 0;
274 }
275 else {
276 TIXMLASSERT( firstChild == 0 );
277 firstChild = lastChild = addThis;
278
279 addThis->parent = this;
280 addThis->prev = 0;
281 addThis->next = 0;
282 }
Lee Thomason67d61312012-01-24 16:01:51 -0800283 if ( addThis->ToText() ) {
284 SetTextParent();
285 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800286 return addThis;
287}
288
289
Lee Thomason5cae8972012-01-24 18:03:07 -0800290void XMLNode::Print( XMLStreamer* streamer )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800291{
292 for( XMLNode* node = firstChild; node; node=node->next ) {
Lee Thomason5cae8972012-01-24 18:03:07 -0800293 node->Print( streamer );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800294 }
295}
296
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800297
Lee Thomason67d61312012-01-24 16:01:51 -0800298char* XMLNode::ParseDeep( char* p )
299{
300 while( p && *p ) {
301 XMLNode* node = 0;
302 p = Identify( document, p, &node );
303 if ( p && node ) {
304 p = node->ParseDeep( p );
305 // FIXME: is it the correct closing element?
306 if ( node->IsClosingElement() ) {
307 delete node;
308 return p;
309 }
310 this->InsertEndChild( node );
311 }
312 }
313 return 0;
314}
315
Lee Thomason5492a1c2012-01-23 15:32:10 -0800316// --------- XMLText ---------- //
317char* XMLText::ParseDeep( char* p )
318{
319 p = ParseText( p, &value, "<" );
320 // consumes the end tag.
321 if ( p && *p ) {
322 return p-1;
323 }
324 return 0;
325}
326
327
Lee Thomason5cae8972012-01-24 18:03:07 -0800328void XMLText::Print( XMLStreamer* streamer )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800329{
Lee Thomason67d61312012-01-24 16:01:51 -0800330 const char* v = value.GetStr();
Lee Thomason5cae8972012-01-24 18:03:07 -0800331 streamer->PushText( v );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800332}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800333
334
Lee Thomason3f57d272012-01-11 15:30:03 -0800335// --------- XMLComment ---------- //
336
Lee Thomasone4422302012-01-20 17:59:50 -0800337XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800338{
339}
340
341
Lee Thomasonce0763e2012-01-11 15:43:54 -0800342XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800343{
Lee Thomasond923c672012-01-23 08:44:25 -0800344 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800345}
346
347
Lee Thomason5cae8972012-01-24 18:03:07 -0800348void XMLComment::Print( XMLStreamer* streamer )
Lee Thomasonce0763e2012-01-11 15:43:54 -0800349{
Lee Thomason5cae8972012-01-24 18:03:07 -0800350// XMLNode::Print( fp, depth );
351// fprintf( fp, "<!--%s-->\n", value.GetStr() );
352 streamer->PushComment( value.GetStr() );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800353}
354
355
356char* XMLComment::ParseDeep( char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800357{
358 // Comment parses as text.
Lee Thomasone4422302012-01-20 17:59:50 -0800359 return ParseText( p, &value, "-->" );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800360}
361
362
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800363// --------- XMLAttribute ---------- //
364char* XMLAttribute::ParseDeep( char* p )
365{
Lee Thomason22aead12012-01-23 13:29:35 -0800366 p = ParseText( p, &name, "=" );
367 if ( !p || !*p ) return 0;
368
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800369 char endTag[2] = { *p, 0 };
370 ++p;
Lee Thomasone4422302012-01-20 17:59:50 -0800371 p = ParseText( p, &value, endTag );
372 if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800373 return p;
374}
375
376
Lee Thomason5cae8972012-01-24 18:03:07 -0800377void XMLAttribute::Print( XMLStreamer* streamer )
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800378{
Lee Thomason22aead12012-01-23 13:29:35 -0800379 // fixme: sort out single vs. double quote
Lee Thomason5cae8972012-01-24 18:03:07 -0800380 //fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() );
381 streamer->PushAttribute( name.GetStr(), value.GetStr() );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800382}
383
384
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800385// --------- XMLElement ---------- //
386XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800387 closing( false ),
388 rootAttribute( 0 ),
389 lastAttribute( 0 )
390{
391}
392
393
394XMLElement::~XMLElement()
395{
Lee Thomasond923c672012-01-23 08:44:25 -0800396 //printf( "~XMLElemen %x\n",this );
397
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800398 XMLAttribute* attribute = rootAttribute;
399 while( attribute ) {
400 XMLAttribute* next = attribute->next;
401 delete attribute;
402 attribute = next;
403 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800404}
405
406
Lee Thomason67d61312012-01-24 16:01:51 -0800407char* XMLElement::ParseAttributes( char* p, bool* closedElement )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800408{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800409 const char* start = p;
Lee Thomason67d61312012-01-24 16:01:51 -0800410 *closedElement = false;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800411
412 // Read the attributes.
413 while( p ) {
414 p = SkipWhiteSpace( p );
415 if ( !p || !(*p) ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800416 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, name.GetStr() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800417 return 0;
418 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800419
420 // attribute.
Lee Thomason22aead12012-01-23 13:29:35 -0800421 if ( IsAlpha( *p ) ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800422 XMLAttribute* attrib = new XMLAttribute( this );
423 p = attrib->ParseDeep( p );
424 if ( !p ) {
425 delete attrib;
Lee Thomasone4422302012-01-20 17:59:50 -0800426 document->SetError( XMLDocument::ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800427 return 0;
428 }
429 if ( rootAttribute ) {
430 TIXMLASSERT( lastAttribute );
431 lastAttribute->next = attrib;
432 lastAttribute = attrib;
433 }
434 else {
435 rootAttribute = lastAttribute = attrib;
436 }
437 }
Lee Thomasone4422302012-01-20 17:59:50 -0800438 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800439 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800440 if ( closing ) {
441 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
442 return 0;
443 }
Lee Thomason67d61312012-01-24 16:01:51 -0800444 *closedElement = true;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800445 return p+2; // done; sealed element.
446 }
Lee Thomasone4422302012-01-20 17:59:50 -0800447 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800448 else if ( *p == '>' ) {
449 ++p;
450 break;
451 }
Lee Thomasone4422302012-01-20 17:59:50 -0800452 else {
453 document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
454 return 0;
455 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800456 }
Lee Thomason67d61312012-01-24 16:01:51 -0800457 return p;
458}
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800459
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800460
Lee Thomason67d61312012-01-24 16:01:51 -0800461//
462// <ele></ele>
463// <ele>foo<b>bar</b></ele>
464//
465char* XMLElement::ParseDeep( char* p )
466{
467 // Read the element name.
468 p = SkipWhiteSpace( p );
469 if ( !p ) return 0;
470 const char* start = p;
471
472 // The closing element is the </element> form. It is
473 // parsed just like a regular element then deleted from
474 // the DOM.
475 if ( *p == '/' ) {
476 closing = true;
477 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800478 }
Lee Thomason67d61312012-01-24 16:01:51 -0800479
480 p = ParseName( p, &name );
481 if ( name.Empty() ) return 0;
482
483 bool elementClosed=false;
484 p = ParseAttributes( p, &elementClosed );
485 if ( !p || !*p || elementClosed || closing )
486 return p;
487
488 p = XMLNode::ParseDeep( p );
489 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800490}
491
492
Lee Thomason5cae8972012-01-24 18:03:07 -0800493void XMLElement::Print( XMLStreamer* streamer )
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800494{
Lee Thomason5cae8972012-01-24 18:03:07 -0800495 //if ( !parent || !parent->IsTextParent() ) {
496 // PrintSpace( cfile, depth );
497 //}
498 //fprintf( cfile, "<%s", Name() );
499 streamer->OpenElement( Name(), IsTextParent() );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800500
501 for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
Lee Thomason5cae8972012-01-24 18:03:07 -0800502 //fprintf( cfile, " " );
503 attrib->Print( streamer );
504
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800505 }
506
Lee Thomason5cae8972012-01-24 18:03:07 -0800507 for( XMLNode* node=firstChild; node; node=node->next ) {
508 node->Print( streamer );
509 }
510 streamer->CloseElement();
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800511}
512
513
Lee Thomason3f57d272012-01-11 15:30:03 -0800514// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -0800515XMLDocument::XMLDocument() :
516 XMLNode( this ),
U-Lama\Lee560bd472011-12-28 19:42:49 -0800517 charBuffer( 0 )
518{
519}
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800520
521
Lee Thomason3f57d272012-01-11 15:30:03 -0800522XMLDocument::~XMLDocument()
523{
Lee Thomason3f57d272012-01-11 15:30:03 -0800524}
525
526
527
528bool XMLDocument::Parse( const char* p )
529{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800530 charBuffer = CharBuffer::Construct( p );
Lee Thomason3f57d272012-01-11 15:30:03 -0800531 XMLNode* node = 0;
Lee Thomason85403d82012-01-11 15:55:05 -0800532
Lee Thomason67d61312012-01-24 16:01:51 -0800533 char* q = ParseDeep( charBuffer->mem );
534 return true;
Lee Thomason3f57d272012-01-11 15:30:03 -0800535}
536
537
Lee Thomason5cae8972012-01-24 18:03:07 -0800538void XMLDocument::Print( XMLStreamer* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -0800539{
Lee Thomason5cae8972012-01-24 18:03:07 -0800540 XMLStreamer stdStreamer( stdout );
541 if ( !streamer )
542 streamer = &stdStreamer;
Lee Thomason67d61312012-01-24 16:01:51 -0800543 for( XMLNode* node = firstChild; node; node=node->next ) {
Lee Thomason5cae8972012-01-24 18:03:07 -0800544 node->Print( streamer );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800545 }
Lee Thomason3f57d272012-01-11 15:30:03 -0800546}
547
548
Lee Thomason67d61312012-01-24 16:01:51 -0800549void XMLDocument::SetError( int error, const char* str1, const char* str2 )
550{
551 printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 );
552}
553
Lee Thomason5cae8972012-01-24 18:03:07 -0800554
555StringStack::StringStack()
556{
Lee Thomason24767b02012-01-25 17:16:23 -0800557 *pool = 0;
558 mem = pool;
Lee Thomason5cae8972012-01-24 18:03:07 -0800559 inUse = 1; // always has a null
560 allocated = INIT;
561 nPositive = 0;
562}
563
564
Lee Thomason24767b02012-01-25 17:16:23 -0800565StringStack::~StringStack()
566{
567 if ( mem != pool ) {
568 delete [] mem;
569 }
570}
571
572
Lee Thomason5cae8972012-01-24 18:03:07 -0800573void StringStack::Push( const char* str ) {
574 int needed = strlen( str ) + 1;
575 if ( needed > 1 )
576 nPositive++;
577 if ( inUse+needed > allocated ) {
578 // fixme: power of 2
579 // less stupid allocation
580 int more = inUse+needed + 1000;
581
582 char* newMem = new char[more];
583 memcpy( newMem, mem, inUse );
Lee Thomason24767b02012-01-25 17:16:23 -0800584 if ( mem != pool ) {
585 delete [] mem;
586 }
Lee Thomason5cae8972012-01-24 18:03:07 -0800587 mem = newMem;
588 }
589 strcpy( mem+inUse, str );
590 inUse += needed;
591}
592
593
594const char* StringStack::Pop() {
595 TIXMLASSERT( inUse > 1 );
596 const char* p = mem+inUse-2;
597 if ( *p ) {
598 nPositive--;
599 }
600 while( *p ) { // stack starts with a null, don't need to check for 'mem'
601 TIXMLASSERT( p > mem );
602 --p;
603 }
604 inUse = p-mem+1;
605 return p+1;
606}
607
608
609XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
610{
611}
612
613
614void XMLStreamer::PrintSpace( int depth )
615{
616 for( int i=0; i<depth; ++i ) {
617 fprintf( fp, " " );
618 }
619}
620
621
622void XMLStreamer::OpenElement( const char* name, bool textParent )
623{
624 if ( elementJustOpened ) {
625 SealElement();
626 }
Lee Thomason24767b02012-01-25 17:16:23 -0800627 if ( text.NumPositive() == 0 ) {
628 PrintSpace( depth );
629 }
Lee Thomason5cae8972012-01-24 18:03:07 -0800630 stack.Push( name );
631 text.Push( textParent ? "T" : "" );
632
Lee Thomason5cae8972012-01-24 18:03:07 -0800633 fprintf( fp, "<%s", name );
634 elementJustOpened = true;
635 ++depth;
636}
637
638
639void XMLStreamer::PushAttribute( const char* name, const char* value )
640{
641 TIXMLASSERT( elementJustOpened );
642 fprintf( fp, " %s=\"%s\"", name, value );
643}
644
645
646void XMLStreamer::CloseElement()
647{
648 --depth;
649 const char* name = stack.Pop();
Lee Thomason24767b02012-01-25 17:16:23 -0800650 int wasPositive = text.NumPositive();
Lee Thomason5cae8972012-01-24 18:03:07 -0800651 text.Pop();
652
653 if ( elementJustOpened ) {
654 fprintf( fp, "/>" );
655 if ( text.NumPositive() == 0 ) {
656 fprintf( fp, "\n" );
657 }
658 }
659 else {
Lee Thomason24767b02012-01-25 17:16:23 -0800660 if ( wasPositive == 0 ) {
661 PrintSpace( depth );
662 }
Lee Thomason5cae8972012-01-24 18:03:07 -0800663 fprintf( fp, "</%s>", name );
664 if ( text.NumPositive() == 0 ) {
665 fprintf( fp, "\n" );
666 }
667 }
668 elementJustOpened = false;
669}
670
671
672void XMLStreamer::SealElement()
673{
674 elementJustOpened = false;
675 fprintf( fp, ">" );
676 if ( text.NumPositive() == 0 ) {
677 fprintf( fp, "\n" );
678 }
679}
680
681
682void XMLStreamer::PushText( const char* text )
683{
684 if ( elementJustOpened ) {
685 SealElement();
686 }
687 fprintf( fp, "%s", text );
688}
689
690
691void XMLStreamer::PushComment( const char* comment )
692{
693 if ( elementJustOpened ) {
694 SealElement();
695 }
696 PrintSpace( depth );
697 fprintf( fp, "<!--%s-->\n", comment );
698}