blob: 61153462569008ef0320eda787c93d561d367913 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
26#include <string.h>
27#include <stdlib.h>
28#include <stdio.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -080029#include <ctype.h>
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080030#include <new>
U-Stream\Leeae25a442012-02-17 17:48:16 -080031#include <stdarg.h>
Lee Thomasond1983222012-02-06 08:41:24 -080032
U-Lama\Lee560bd472011-12-28 19:42:49 -080033
34using namespace tinyxml2;
35
Lee Thomasone4422302012-01-20 17:59:50 -080036static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080037static const char LF = LINE_FEED;
38static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
39static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080040static const char SINGLE_QUOTE = '\'';
41static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080042
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080043// Bunch of unicode info at:
44// http://www.unicode.org/faq/utf_bom.html
45// ef bb bf (Microsoft "lead bytes") - designates UTF-8
46
47static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
48static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
49static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080050
51
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080052#define DELETE_NODE( node ) { \
53 if ( node ) { \
54 MemPool* pool = node->memPool; \
55 node->~XMLNode(); \
56 pool->Free( node ); \
57 } \
58}
59#define DELETE_ATTRIBUTE( attrib ) { \
60 if ( attrib ) { \
61 MemPool* pool = attrib->memPool; \
62 attrib->~XMLAttribute(); \
63 pool->Free( attrib ); \
64 } \
65}
Lee Thomason43f59302012-02-06 18:18:11 -080066
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
68 const char* pattern;
69 int length;
70 char value;
71};
72
73static const int NUM_ENTITIES = 5;
74static const Entity entities[NUM_ENTITIES] =
75{
Lee Thomason18d68bd2012-01-26 18:17:26 -080076 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080077 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080078 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080079 { "lt", 2, '<' },
80 { "gt", 2, '>' }
81};
82
Lee Thomasonfde6a752012-01-14 18:08:12 -080083
Lee Thomason1a1d4a72012-02-15 09:09:25 -080084StrPair::~StrPair()
85{
86 Reset();
87}
88
89
90void StrPair::Reset()
91{
92 if ( flags & NEEDS_DELETE ) {
93 delete [] start;
94 }
95 flags = 0;
96 start = 0;
97 end = 0;
98}
99
100
101void StrPair::SetStr( const char* str, int flags )
102{
103 Reset();
104 size_t len = strlen( str );
105 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800106 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800107 end = start + len;
108 this->flags = flags | NEEDS_DELETE;
109}
110
111
112char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
113{
114 TIXMLASSERT( endTag && *endTag );
115
116 char* start = p; // fixme: hides a member
117 char endChar = *endTag;
118 int length = strlen( endTag );
119
120 // Inner loop of text parsing.
121 while ( *p ) {
122 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
123 Set( start, p, strFlags );
124 return p + length;
125 }
126 ++p;
127 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800128 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800129}
130
131
132char* StrPair::ParseName( char* p )
133{
134 char* start = p;
135
136 start = p;
137 if ( !start || !(*start) ) {
138 return 0;
139 }
140
141 if ( !XMLUtil::IsAlpha( *p ) ) {
142 return 0;
143 }
144
145 while( *p && (
146 XMLUtil::IsAlphaNum( (unsigned char) *p )
147 || *p == '_'
148 || *p == '-'
149 || *p == '.'
150 || *p == ':' ))
151 {
152 ++p;
153 }
154
155 if ( p > start ) {
156 Set( start, p, 0 );
157 return p;
158 }
159 return 0;
160}
161
162
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163
Lee Thomasone4422302012-01-20 17:59:50 -0800164const char* StrPair::GetStr()
165{
166 if ( flags & NEEDS_FLUSH ) {
167 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800168 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800169
Lee Thomason8ee79892012-01-25 17:44:30 -0800170 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800171 char* p = start; // the read pointer
172 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800173
174 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800175 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800176 // CR-LF pair becomes LF
177 // CR alone becomes LF
178 // LF-CR becomes LF
179 if ( *(p+1) == LF ) {
180 p += 2;
181 }
182 else {
183 ++p;
184 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800185 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800186 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800187 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800188 if ( *(p+1) == CR ) {
189 p += 2;
190 }
191 else {
192 ++p;
193 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800194 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800195 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800196 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
197 int i=0;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800198
199 // Entities handled by tinyXML2:
200 // - special entities in the entity table [in/out]
201 // - numeric character reference [in]
202 // &#20013; or &#x4e2d;
203
204 if ( *(p+1) == '#' ) {
205 char buf[10] = { 0 };
206 int len;
207 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
208 for( int i=0; i<len; ++i ) {
209 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800210 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800211 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800212 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800213 else {
214 for( i=0; i<NUM_ENTITIES; ++i ) {
215 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
216 && *(p+entities[i].length+1) == ';' )
217 {
218 // Found an entity convert;
219 *q = entities[i].value;
220 ++q;
221 p += entities[i].length + 2;
222 break;
223 }
224 }
225 if ( i == NUM_ENTITIES ) {
226 // fixme: treat as error?
227 ++p;
228 ++q;
229 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800230 }
231 }
Lee Thomasone4422302012-01-20 17:59:50 -0800232 else {
233 *q = *p;
234 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800235 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800236 }
237 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800238 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800239 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800240 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800241 }
242 return start;
243}
244
Lee Thomason2c85a712012-01-31 08:24:24 -0800245
Lee Thomasone4422302012-01-20 17:59:50 -0800246
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800247
Lee Thomason56bdd022012-02-09 18:16:58 -0800248// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800249
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800250const char* XMLUtil::ReadBOM( const char* p, bool* bom )
251{
252 *bom = false;
253 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
254 // Check for BOM:
255 if ( *(pu+0) == TIXML_UTF_LEAD_0
256 && *(pu+1) == TIXML_UTF_LEAD_1
257 && *(pu+2) == TIXML_UTF_LEAD_2 )
258 {
259 *bom = true;
260 p += 3;
261 }
262 return p;
263}
264
265
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800266void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
267{
268 const unsigned long BYTE_MASK = 0xBF;
269 const unsigned long BYTE_MARK = 0x80;
270 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
271
272 if (input < 0x80)
273 *length = 1;
274 else if ( input < 0x800 )
275 *length = 2;
276 else if ( input < 0x10000 )
277 *length = 3;
278 else if ( input < 0x200000 )
279 *length = 4;
280 else
281 { *length = 0; return; } // This code won't covert this correctly anyway.
282
283 output += *length;
284
285 // Scary scary fall throughs.
286 switch (*length)
287 {
288 case 4:
289 --output;
290 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
291 input >>= 6;
292 case 3:
293 --output;
294 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
295 input >>= 6;
296 case 2:
297 --output;
298 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
299 input >>= 6;
300 case 1:
301 --output;
302 *output = (char)(input | FIRST_BYTE_MARK[*length]);
303 }
304}
305
306
307const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
308{
309 // Presume an entity, and pull it out.
310 *length = 0;
311
312 if ( *(p+1) == '#' && *(p+2) )
313 {
314 unsigned long ucs = 0;
315 ptrdiff_t delta = 0;
316 unsigned mult = 1;
317
318 if ( *(p+2) == 'x' )
319 {
320 // Hexadecimal.
321 if ( !*(p+3) ) return 0;
322
323 const char* q = p+3;
324 q = strchr( q, ';' );
325
326 if ( !q || !*q ) return 0;
327
328 delta = q-p;
329 --q;
330
331 while ( *q != 'x' )
332 {
333 if ( *q >= '0' && *q <= '9' )
334 ucs += mult * (*q - '0');
335 else if ( *q >= 'a' && *q <= 'f' )
336 ucs += mult * (*q - 'a' + 10);
337 else if ( *q >= 'A' && *q <= 'F' )
338 ucs += mult * (*q - 'A' + 10 );
339 else
340 return 0;
341 mult *= 16;
342 --q;
343 }
344 }
345 else
346 {
347 // Decimal.
348 if ( !*(p+2) ) return 0;
349
350 const char* q = p+2;
351 q = strchr( q, ';' );
352
353 if ( !q || !*q ) return 0;
354
355 delta = q-p;
356 --q;
357
358 while ( *q != '#' )
359 {
360 if ( *q >= '0' && *q <= '9' )
361 ucs += mult * (*q - '0');
362 else
363 return 0;
364 mult *= 10;
365 --q;
366 }
367 }
368 // convert the UCS to UTF-8
369 ConvertUTF32ToUTF8( ucs, value, length );
370 return p + delta + 1;
371 }
372 return p+1;
373}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800374
375
Lee Thomasond1983222012-02-06 08:41:24 -0800376char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800377{
378 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800379 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800380 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800381 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800382 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800383 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800384 }
385
386 // What is this thing?
387 // - Elements start with a letter or underscore, but xml is reserved.
388 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800389 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800390 // - Everthing else is unknown to tinyxml.
391 //
392
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800393 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800394 static const char* commentHeader = { "<!--" };
395 static const char* dtdHeader = { "<!" };
396 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800397 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800398
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800399 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800400 static const int commentHeaderLen = 4;
401 static const int dtdHeaderLen = 2;
402 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800403 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800404
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800405#pragma warning ( push )
406#pragma warning ( disable : 4127 )
Lee Thomason50f97b22012-02-11 16:33:40 -0800407 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
408 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800409#pragma warning (pop)
Lee Thomason50f97b22012-02-11 16:33:40 -0800410
411 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
412 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
413 returnNode->memPool = &commentPool;
414 p += xmlHeaderLen;
415 }
416 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800417 returnNode = new (commentPool.Alloc()) XMLComment( this );
418 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800419 p += commentHeaderLen;
420 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800421 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
422 XMLText* text = new (textPool.Alloc()) XMLText( this );
423 returnNode = text;
424 returnNode->memPool = &textPool;
425 p += cdataHeaderLen;
426 text->SetCData( true );
427 }
428 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
429 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
430 returnNode->memPool = &commentPool;
431 p += dtdHeaderLen;
432 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800433 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800434 returnNode = new (elementPool.Alloc()) XMLElement( this );
435 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800436 p += elementHeaderLen;
437 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800438 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800439 returnNode = new (textPool.Alloc()) XMLText( this );
440 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800441 p = start; // Back it up, all the text counts.
442 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800443
444 *node = returnNode;
445 return p;
446}
447
448
Lee Thomason751da522012-02-10 08:50:51 -0800449bool XMLDocument::Accept( XMLVisitor* visitor ) const
450{
451 if ( visitor->VisitEnter( *this ) )
452 {
453 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
454 {
455 if ( !node->Accept( visitor ) )
456 break;
457 }
458 }
459 return visitor->VisitExit( *this );
460}
Lee Thomason56bdd022012-02-09 18:16:58 -0800461
462
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800463// --------- XMLNode ----------- //
464
465XMLNode::XMLNode( XMLDocument* doc ) :
466 document( doc ),
467 parent( 0 ),
468 firstChild( 0 ), lastChild( 0 ),
469 prev( 0 ), next( 0 )
470{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800471}
472
473
474XMLNode::~XMLNode()
475{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800476 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800477 if ( parent ) {
478 parent->Unlink( this );
479 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800480}
481
482
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800483void XMLNode::SetValue( const char* str, bool staticMem )
484{
485 if ( staticMem )
486 value.SetInternedStr( str );
487 else
488 value.SetStr( str );
489}
490
491
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800492void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800493{
Lee Thomasond923c672012-01-23 08:44:25 -0800494 while( firstChild ) {
495 XMLNode* node = firstChild;
496 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800497
Lee Thomason43f59302012-02-06 18:18:11 -0800498 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800499 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800500 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800501}
502
503
504void XMLNode::Unlink( XMLNode* child )
505{
506 TIXMLASSERT( child->parent == this );
507 if ( child == firstChild )
508 firstChild = firstChild->next;
509 if ( child == lastChild )
510 lastChild = lastChild->prev;
511
512 if ( child->prev ) {
513 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514 }
Lee Thomasond923c672012-01-23 08:44:25 -0800515 if ( child->next ) {
516 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517 }
Lee Thomasond923c672012-01-23 08:44:25 -0800518 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519}
520
521
U-Stream\Leeae25a442012-02-17 17:48:16 -0800522void XMLNode::DeleteChild( XMLNode* node )
523{
524 TIXMLASSERT( node->parent == this );
525 DELETE_NODE( node );
526}
527
528
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800529XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
530{
531 if ( lastChild ) {
532 TIXMLASSERT( firstChild );
533 TIXMLASSERT( lastChild->next == 0 );
534 lastChild->next = addThis;
535 addThis->prev = lastChild;
536 lastChild = addThis;
537
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800538 addThis->next = 0;
539 }
540 else {
541 TIXMLASSERT( firstChild == 0 );
542 firstChild = lastChild = addThis;
543
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800544 addThis->prev = 0;
545 addThis->next = 0;
546 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800547 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800548 return addThis;
549}
550
551
Lee Thomason1ff38e02012-02-14 18:18:16 -0800552XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
553{
554 if ( firstChild ) {
555 TIXMLASSERT( lastChild );
556 TIXMLASSERT( firstChild->prev == 0 );
557
558 firstChild->prev = addThis;
559 addThis->next = firstChild;
560 firstChild = addThis;
561
Lee Thomason1ff38e02012-02-14 18:18:16 -0800562 addThis->prev = 0;
563 }
564 else {
565 TIXMLASSERT( lastChild == 0 );
566 firstChild = lastChild = addThis;
567
Lee Thomason1ff38e02012-02-14 18:18:16 -0800568 addThis->prev = 0;
569 addThis->next = 0;
570 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800571 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800572 return addThis;
573}
574
575
576XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
577{
578 TIXMLASSERT( afterThis->parent == this );
579 if ( afterThis->parent != this )
580 return 0;
581
582 if ( afterThis->next == 0 ) {
583 // The last node or the only node.
584 return InsertEndChild( addThis );
585 }
586 addThis->prev = afterThis;
587 addThis->next = afterThis->next;
588 afterThis->next->prev = addThis;
589 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800590 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800591 return addThis;
592}
593
594
595
596
Lee Thomason56bdd022012-02-09 18:16:58 -0800597const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800598{
599 for( XMLNode* node=firstChild; node; node=node->next ) {
600 XMLElement* element = node->ToElement();
601 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800602 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800603 return element;
604 }
605 }
606 }
607 return 0;
608}
609
610
Lee Thomason56bdd022012-02-09 18:16:58 -0800611const XMLElement* XMLNode::LastChildElement( const char* value ) const
612{
613 for( XMLNode* node=lastChild; node; node=node->prev ) {
614 XMLElement* element = node->ToElement();
615 if ( element ) {
616 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
617 return element;
618 }
619 }
620 }
621 return 0;
622}
623
624
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800625char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800626{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800627 // This is a recursive method, but thinking about it "at the current level"
628 // it is a pretty simple flat list:
629 // <foo/>
630 // <!-- comment -->
631 //
632 // With a special case:
633 // <foo>
634 // </foo>
635 // <!-- comment -->
636 //
637 // Where the closing element (/foo) *must* be the next thing after the opening
638 // element, and the names must match. BUT the tricky bit is that the closing
639 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800640 //
641 // 'endTag' is the end tag for this node, it is returned by a call to a child.
642 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800643
Lee Thomason67d61312012-01-24 16:01:51 -0800644 while( p && *p ) {
645 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800646
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800647 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800648 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800649 break;
650 }
651
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800652 StrPair endTag;
653 p = node->ParseDeep( p, &endTag );
654 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800655 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800656 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800657 if ( !document->Error() ) {
658 document->SetError( ERROR_PARSING, 0, 0 );
659 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800660 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800661 }
662
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800663 // We read the end tag. Return it to the parent.
664 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
665 if ( parentEnd ) {
666 *parentEnd = ((XMLElement*)node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800667 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800668 DELETE_NODE( node );
669 return p;
670 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800671
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800672 // Handle an end tag returned to this level.
673 // And handle a bunch of annoying errors.
674 XMLElement* ele = node->ToElement();
675 if ( ele ) {
676 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
677 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
678 p = 0;
679 }
680 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
681 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
682 p = 0;
683 }
684 else if ( !endTag.Empty() ) {
685 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800686 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
687 p = 0;
688 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800689 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800690 }
691 if ( p == 0 ) {
692 DELETE_NODE( node );
693 node = 0;
694 }
695 if ( node ) {
696 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800697 }
698 }
699 return 0;
700}
701
Lee Thomason5492a1c2012-01-23 15:32:10 -0800702// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800703char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800704{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800705 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800706 if ( this->CData() ) {
707 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800708 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800709 document->SetError( ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800710 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800711 return p;
712 }
713 else {
714 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800715 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800716 document->SetError( ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800717 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800718 if ( p && *p ) {
719 return p-1;
720 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800721 }
722 return 0;
723}
724
725
Lee Thomason56bdd022012-02-09 18:16:58 -0800726bool XMLText::Accept( XMLVisitor* visitor ) const
727{
728 return visitor->Visit( *this );
729}
730
731
Lee Thomason3f57d272012-01-11 15:30:03 -0800732// --------- XMLComment ---------- //
733
Lee Thomasone4422302012-01-20 17:59:50 -0800734XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800735{
736}
737
738
Lee Thomasonce0763e2012-01-11 15:43:54 -0800739XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800740{
Lee Thomasond923c672012-01-23 08:44:25 -0800741 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800742}
743
744
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800745char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800746{
747 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800748 const char* start = p;
749 p = value.ParseText( p, "-->", StrPair::COMMENT );
750 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800751 document->SetError( ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800752 }
753 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800754}
755
756
Lee Thomason751da522012-02-10 08:50:51 -0800757bool XMLComment::Accept( XMLVisitor* visitor ) const
758{
759 return visitor->Visit( *this );
760}
Lee Thomason56bdd022012-02-09 18:16:58 -0800761
762
Lee Thomason50f97b22012-02-11 16:33:40 -0800763// --------- XMLDeclaration ---------- //
764
765XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
766{
767}
768
769
770XMLDeclaration::~XMLDeclaration()
771{
772 //printf( "~XMLDeclaration\n" );
773}
774
775
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800776char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800777{
778 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800779 const char* start = p;
780 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
781 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800782 document->SetError( ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800783 }
784 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800785}
786
787
788bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
789{
790 return visitor->Visit( *this );
791}
792
793// --------- XMLUnknown ---------- //
794
795XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
796{
797}
798
799
800XMLUnknown::~XMLUnknown()
801{
802}
803
804
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800805char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800806{
807 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800808 const char* start = p;
809
810 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
811 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800812 document->SetError( ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800813 }
814 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800815}
816
817
818bool XMLUnknown::Accept( XMLVisitor* visitor ) const
819{
820 return visitor->Visit( *this );
821}
822
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823// --------- XMLAttribute ---------- //
824char* XMLAttribute::ParseDeep( char* p )
825{
Lee Thomason56bdd022012-02-09 18:16:58 -0800826 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800827 if ( !p || !*p ) return 0;
828
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800829 char endTag[2] = { *p, 0 };
830 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800831 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832 //if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833 return p;
834}
835
836
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800837void XMLAttribute::SetName( const char* n )
838{
839 name.SetStr( n );
840}
841
842
Lee Thomason1ff38e02012-02-14 18:18:16 -0800843int XMLAttribute::QueryIntAttribute( int* value ) const
844{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800845 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800846 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847 return WRONG_ATTRIBUTE_TYPE;
848}
849
850
851int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
852{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800853 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800854 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800855 return WRONG_ATTRIBUTE_TYPE;
856}
857
858
859int XMLAttribute::QueryBoolAttribute( bool* value ) const
860{
861 int ival = -1;
862 QueryIntAttribute( &ival );
863
864 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
865 *value = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800866 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800867 }
868 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
869 *value = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800870 return XML_NO_ERROR;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800871 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800872 return WRONG_ATTRIBUTE_TYPE;
873}
874
875
876int XMLAttribute::QueryDoubleAttribute( double* value ) const
877{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800878 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800879 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880 return WRONG_ATTRIBUTE_TYPE;
881}
882
883
884int XMLAttribute::QueryFloatAttribute( float* value ) const
885{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800886 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800887 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800888 return WRONG_ATTRIBUTE_TYPE;
889}
890
891
892void XMLAttribute::SetAttribute( const char* v )
893{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800894 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800895}
896
897
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898void XMLAttribute::SetAttribute( int v )
899{
900 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800901 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
902 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800903}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800904
905
906void XMLAttribute::SetAttribute( unsigned v )
907{
908 char buf[BUF_SIZE];
909 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
910 value.SetStr( buf );
911}
912
913
914void XMLAttribute::SetAttribute( bool v )
915{
916 char buf[BUF_SIZE];
917 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
918 value.SetStr( buf );
919}
920
921void XMLAttribute::SetAttribute( double v )
922{
923 char buf[BUF_SIZE];
924 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
925 value.SetStr( buf );
926}
927
928void XMLAttribute::SetAttribute( float v )
929{
930 char buf[BUF_SIZE];
931 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
932 value.SetStr( buf );
933}
934
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800935
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800936// --------- XMLElement ---------- //
937XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800938 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800939 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800940{
941}
942
943
944XMLElement::~XMLElement()
945{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800946 while( rootAttribute ) {
947 XMLAttribute* next = rootAttribute->next;
948 DELETE_ATTRIBUTE( rootAttribute );
949 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800950 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800951}
952
953
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800954XMLAttribute* XMLElement::FindAttribute( const char* name )
955{
956 XMLAttribute* a = 0;
957 for( a=rootAttribute; a; a = a->next ) {
958 if ( XMLUtil::StringEqual( a->Name(), name ) )
959 return a;
960 }
961 return 0;
962}
963
964
965const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
966{
967 XMLAttribute* a = 0;
968 for( a=rootAttribute; a; a = a->next ) {
969 if ( XMLUtil::StringEqual( a->Name(), name ) )
970 return a;
971 }
972 return 0;
973}
974
975
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800976const char* XMLElement::GetText() const
977{
978 if ( FirstChild() && FirstChild()->ToText() ) {
979 return FirstChild()->ToText()->Value();
980 }
981 return 0;
982}
983
984
985
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800986XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
987{
988 XMLAttribute* attrib = FindAttribute( name );
989 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800990 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800991 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800992 LinkAttribute( attrib );
993 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800994 }
995 return attrib;
996}
997
998
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800999void XMLElement::LinkAttribute( XMLAttribute* attrib )
1000{
1001 if ( rootAttribute ) {
1002 XMLAttribute* end = rootAttribute;
1003 while ( end->next )
1004 end = end->next;
1005 end->next = attrib;
1006 }
1007 else {
1008 rootAttribute = attrib;
1009 }
1010}
1011
1012
U-Stream\Leeae25a442012-02-17 17:48:16 -08001013void XMLElement::DeleteAttribute( const char* name )
1014{
1015 XMLAttribute* prev = 0;
1016 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1017 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1018 if ( prev ) {
1019 prev->next = a->next;
1020 }
1021 else {
1022 rootAttribute = a->next;
1023 }
1024 DELETE_ATTRIBUTE( a );
1025 break;
1026 }
1027 prev = a;
1028 }
1029}
1030
1031
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001032char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001033{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001034 const char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001035
1036 // Read the attributes.
1037 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001038 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001039 if ( !p || !(*p) ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001040 document->SetError( ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001041 return 0;
1042 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001043
1044 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001045 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001046 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001047 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001048
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001049 p = attrib->ParseDeep( p );
Lee Thomasond6277762012-02-22 16:00:12 -08001050 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001051 DELETE_ATTRIBUTE( attrib );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001052 document->SetError( ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001053 return 0;
1054 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001055 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001056 }
Lee Thomasone4422302012-01-20 17:59:50 -08001057 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001058 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001060 return p+2; // done; sealed element.
1061 }
Lee Thomasone4422302012-01-20 17:59:50 -08001062 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001063 else if ( *p == '>' ) {
1064 ++p;
1065 break;
1066 }
Lee Thomasone4422302012-01-20 17:59:50 -08001067 else {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001068 document->SetError( ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001069 return 0;
1070 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001071 }
Lee Thomason67d61312012-01-24 16:01:51 -08001072 return p;
1073}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001074
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001075
Lee Thomason67d61312012-01-24 16:01:51 -08001076//
1077// <ele></ele>
1078// <ele>foo<b>bar</b></ele>
1079//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001080char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001081{
1082 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001083 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001084 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001085
1086 // The closing element is the </element> form. It is
1087 // parsed just like a regular element then deleted from
1088 // the DOM.
1089 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001090 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001091 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001092 }
Lee Thomason67d61312012-01-24 16:01:51 -08001093
Lee Thomason56bdd022012-02-09 18:16:58 -08001094 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001095 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001096
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001097 p = ParseAttributes( p );
1098 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001099 return p;
1100
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001101 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
Lee Thomason751da522012-02-10 08:50:51 -08001106bool XMLElement::Accept( XMLVisitor* visitor ) const
1107{
1108 if ( visitor->VisitEnter( *this, rootAttribute ) )
1109 {
1110 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1111 {
1112 if ( !node->Accept( visitor ) )
1113 break;
1114 }
1115 }
1116 return visitor->VisitExit( *this );
1117
1118}
Lee Thomason56bdd022012-02-09 18:16:58 -08001119
Lee Thomason3f57d272012-01-11 15:30:03 -08001120// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -08001121XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001122 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001123 writeBOM( false ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001124 charBuffer( 0 )
1125{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001126 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001127}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001128
1129
Lee Thomason3f57d272012-01-11 15:30:03 -08001130XMLDocument::~XMLDocument()
1131{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001132 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001133 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001134
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001135#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001136 textPool.Trace( "text" );
1137 elementPool.Trace( "element" );
1138 commentPool.Trace( "comment" );
1139 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001140#endif
1141
Lee Thomason455c9d42012-02-06 09:14:14 -08001142 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1143 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1144 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1145 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001146}
1147
1148
Lee Thomason18d68bd2012-01-26 18:17:26 -08001149void XMLDocument::InitDocument()
1150{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001151 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001152 errorStr1 = 0;
1153 errorStr2 = 0;
1154
1155 delete [] charBuffer;
1156 charBuffer = 0;
1157
1158}
1159
Lee Thomason3f57d272012-01-11 15:30:03 -08001160
Lee Thomason2c85a712012-01-31 08:24:24 -08001161XMLElement* XMLDocument::NewElement( const char* name )
1162{
Lee Thomasond1983222012-02-06 08:41:24 -08001163 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1164 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001165 ele->SetName( name );
1166 return ele;
1167}
1168
1169
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170XMLComment* XMLDocument::NewComment( const char* str )
1171{
1172 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1173 comment->memPool = &commentPool;
1174 comment->SetValue( str );
1175 return comment;
1176}
1177
1178
1179XMLText* XMLDocument::NewText( const char* str )
1180{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001181 XMLText* text = new (textPool.Alloc()) XMLText( this );
1182 text->memPool = &textPool;
1183 text->SetValue( str );
1184 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185}
1186
1187
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001188int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001189{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001190 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001191 InitDocument();
1192
1193 FILE* fp = fopen( filename, "rb" );
1194 if ( !fp ) {
1195 SetError( ERROR_FILE_NOT_FOUND, filename, 0 );
1196 return errorID;
1197 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001198 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001199 fclose( fp );
1200 return errorID;
1201}
1202
1203
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001204int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001205{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001206 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001207 InitDocument();
1208
1209 fseek( fp, 0, SEEK_END );
1210 unsigned size = ftell( fp );
1211 fseek( fp, 0, SEEK_SET );
1212
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001213 if ( size == 0 ) {
1214 return errorID;
1215 }
1216
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001217 charBuffer = new char[size+1];
1218 fread( charBuffer, size, 1, fp );
1219 charBuffer[size] = 0;
1220
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001221 const char* p = charBuffer;
1222 p = XMLUtil::SkipWhiteSpace( p );
1223 p = XMLUtil::ReadBOM( p, &writeBOM );
1224 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001225 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1226 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001227 }
1228
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001229 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001230 return errorID;
1231}
1232
1233
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001234void XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001235{
1236 FILE* fp = fopen( filename, "w" );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001237 XMLPrinter stream( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001238 Print( &stream );
1239 fclose( fp );
1240}
1241
Lee Thomason1ff38e02012-02-14 18:18:16 -08001242
Lee Thomason7c913cd2012-01-26 18:32:34 -08001243int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001244{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001245 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001246 InitDocument();
1247
1248 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001249 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1250 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001251 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001252 p = XMLUtil::SkipWhiteSpace( p );
1253 p = XMLUtil::ReadBOM( p, &writeBOM );
1254 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001255 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1256 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001257 }
1258
Lee Thomason18d68bd2012-01-26 18:17:26 -08001259 size_t len = strlen( p );
1260 charBuffer = new char[ len+1 ];
1261 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001263
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001264 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001265 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001266}
1267
1268
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001269void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001270{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001271 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001272 if ( !streamer )
1273 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001274 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001275}
1276
1277
Lee Thomason67d61312012-01-24 16:01:51 -08001278void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1279{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001280 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001281 errorStr1 = str1;
1282 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001283}
1284
Lee Thomason5cae8972012-01-24 18:03:07 -08001285
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001286void XMLDocument::PrintError() const
1287{
1288 if ( errorID ) {
1289 char buf1[20] = { 0 };
1290 char buf2[20] = { 0 };
1291
1292 if ( errorStr1 ) {
1293 strncpy( buf1, errorStr1, 20 );
1294 buf1[19] = 0;
1295 }
1296 if ( errorStr2 ) {
1297 strncpy( buf2, errorStr2, 20 );
1298 buf2[19] = 0;
1299 }
1300
1301 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1302 errorID, buf1, buf2 );
1303 }
1304}
1305
1306
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001307XMLPrinter::XMLPrinter( FILE* file ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001308 elementJustOpened( false ),
1309 firstElement( true ),
1310 fp( file ),
1311 depth( 0 ),
1312 textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -08001313{
Lee Thomason857b8682012-01-25 17:50:25 -08001314 for( int i=0; i<ENTITY_RANGE; ++i ) {
1315 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001316 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001317 }
1318 for( int i=0; i<NUM_ENTITIES; ++i ) {
1319 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1320 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001321 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001322 }
1323 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001324 restrictedEntityFlag[(int)'&'] = true;
1325 restrictedEntityFlag[(int)'<'] = true;
1326 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001327 buffer.Push( 0 );
1328}
1329
1330
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001331void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001332{
1333 va_list va;
1334 va_start( va, format );
1335
1336 if ( fp ) {
1337 vfprintf( fp, format, va );
1338 }
1339 else {
1340 // This seems brutally complex. Haven't figured out a better
1341 // way on windows.
1342 #ifdef _MSC_VER
1343 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001344 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001345 while ( len < 0 ) {
1346 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
1347 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001348 accumulator.PushArr( expand );
1349 expand *= 3/2;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001350 }
1351 }
1352 char* p = buffer.PushArr( len ) - 1;
1353 memcpy( p, accumulator.Mem(), len+1 );
1354 #else
1355 int len = vsnprintf( 0, 0, format, va );
1356 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001357 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001358 #endif
1359 }
1360 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001361}
1362
1363
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001364void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001365{
1366 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001367 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001368 }
1369}
1370
1371
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001372void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001373{
Lee Thomason951d8832012-01-26 08:47:06 -08001374 // Look for runs of bytes between entities to print.
1375 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001376 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001377
Lee Thomason951d8832012-01-26 08:47:06 -08001378 while ( *q ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001379 // Remember, char is sometimes signed. (How many times has that bitten me?)
1380 if ( *q > 0 && *q < ENTITY_RANGE ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001381 // Check for entities. If one is found, flush
1382 // the stream up until the entity, write the
1383 // entity, and keep looking.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001384 if ( flag[*q] ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001385 while ( p < q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001386 Print( "%c", *p );
Lee Thomason951d8832012-01-26 08:47:06 -08001387 ++p;
1388 }
1389 for( int i=0; i<NUM_ENTITIES; ++i ) {
1390 if ( entities[i].value == *q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001391 Print( "&%s;", entities[i].pattern );
Lee Thomason951d8832012-01-26 08:47:06 -08001392 break;
1393 }
1394 }
1395 ++p;
1396 }
1397 }
1398 ++q;
1399 }
1400 // Flush the remaining string. This will be the entire
1401 // string if an entity wasn't found.
1402 if ( q-p > 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001403 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001404 }
Lee Thomason857b8682012-01-25 17:50:25 -08001405}
1406
U-Stream\Leeae25a442012-02-17 17:48:16 -08001407
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001408void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001409{
1410 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1411 if ( writeBOM ) {
1412 Print( "%s", bom );
1413 }
1414 if ( writeDec ) {
1415 PushDeclaration( "xml version=\"1.0\"" );
1416 }
1417}
1418
1419
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001420void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001421{
1422 if ( elementJustOpened ) {
1423 SealElement();
1424 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001425 stack.Push( name );
1426
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001427 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001428 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001429 PrintSpace( depth );
1430 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001431
U-Stream\Leeae25a442012-02-17 17:48:16 -08001432 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001433 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001434 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001435 ++depth;
1436}
1437
1438
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001439void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001440{
1441 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001442 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001443 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001444 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001445}
1446
1447
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001448void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001449{
1450 --depth;
1451 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001452
1453 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001454 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001455 }
1456 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001457 if ( textDepth < 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001458 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001459 PrintSpace( depth );
1460 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001461 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001462 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001463
1464 if ( textDepth == depth )
1465 textDepth = -1;
1466 if ( depth == 0 )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001467 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001468 elementJustOpened = false;
1469}
1470
1471
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001472void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001473{
1474 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001475 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001476}
1477
1478
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001479void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001480{
Lee Thomason56bdd022012-02-09 18:16:58 -08001481 textDepth = depth-1;
1482
Lee Thomason5cae8972012-01-24 18:03:07 -08001483 if ( elementJustOpened ) {
1484 SealElement();
1485 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001486 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001487 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001488 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001489 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001490 }
1491 else {
1492 PrintString( text, true );
1493 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001494}
1495
1496
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001497void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001498{
1499 if ( elementJustOpened ) {
1500 SealElement();
1501 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001502 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001503 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001504 PrintSpace( depth );
1505 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001506 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001507 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001508}
Lee Thomason751da522012-02-10 08:50:51 -08001509
1510
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001511void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001512{
1513 if ( elementJustOpened ) {
1514 SealElement();
1515 }
1516 if ( textDepth < 0 && !firstElement) {
1517 Print( "\n" );
1518 PrintSpace( depth );
1519 }
1520 firstElement = false;
1521 Print( "<?%s?>", value );
1522}
1523
1524
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001525void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001526{
1527 if ( elementJustOpened ) {
1528 SealElement();
1529 }
1530 if ( textDepth < 0 && !firstElement ) {
1531 Print( "\n" );
1532 PrintSpace( depth );
1533 }
1534 firstElement = false;
1535 Print( "<!%s>", value );
1536}
1537
1538
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001539bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001540{
1541 if ( doc.HasBOM() ) {
1542 PushHeader( true, false );
1543 }
1544 return true;
1545}
1546
1547
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001548bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001549{
1550 OpenElement( element.Name() );
1551 while ( attribute ) {
1552 PushAttribute( attribute->Name(), attribute->Value() );
1553 attribute = attribute->Next();
1554 }
1555 return true;
1556}
1557
1558
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001559bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08001560{
1561 CloseElement();
1562 return true;
1563}
1564
1565
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001566bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001567{
Lee Thomasond6277762012-02-22 16:00:12 -08001568 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001569 return true;
1570}
1571
1572
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001573bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08001574{
1575 PushComment( comment.Value() );
1576 return true;
1577}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001578
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001579bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001580{
1581 PushDeclaration( declaration.Value() );
1582 return true;
1583}
1584
1585
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001586bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001587{
1588 PushUnknown( unknown.Value() );
1589 return true;
1590}
1591
1592