blob: e3bf62508b6945aa0d5b113b9b82da1c4e77925f [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 Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080021// Bunch of unicode info at:
22// http://www.unicode.org/faq/utf_bom.html
23// ef bb bf (Microsoft "lead bytes") - designates UTF-8
24
25static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
26static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
27static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080028
29
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080030#define DELETE_NODE( node ) { \
31 if ( node ) { \
32 MemPool* pool = node->memPool; \
33 node->~XMLNode(); \
34 pool->Free( node ); \
35 } \
36}
37#define DELETE_ATTRIBUTE( attrib ) { \
38 if ( attrib ) { \
39 MemPool* pool = attrib->memPool; \
40 attrib->~XMLAttribute(); \
41 pool->Free( attrib ); \
42 } \
43}
Lee Thomason43f59302012-02-06 18:18:11 -080044
Lee Thomason8ee79892012-01-25 17:44:30 -080045struct Entity {
46 const char* pattern;
47 int length;
48 char value;
49};
50
51static const int NUM_ENTITIES = 5;
52static const Entity entities[NUM_ENTITIES] =
53{
Lee Thomason18d68bd2012-01-26 18:17:26 -080054 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080055 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080056 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080057 { "lt", 2, '<' },
58 { "gt", 2, '>' }
59};
60
Lee Thomasonfde6a752012-01-14 18:08:12 -080061
Lee Thomason1a1d4a72012-02-15 09:09:25 -080062StrPair::~StrPair()
63{
64 Reset();
65}
66
67
68void StrPair::Reset()
69{
70 if ( flags & NEEDS_DELETE ) {
71 delete [] start;
72 }
73 flags = 0;
74 start = 0;
75 end = 0;
76}
77
78
79void StrPair::SetStr( const char* str, int flags )
80{
81 Reset();
82 size_t len = strlen( str );
83 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -080084 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085 end = start + len;
86 this->flags = flags | NEEDS_DELETE;
87}
88
89
90char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
91{
92 TIXMLASSERT( endTag && *endTag );
93
94 char* start = p; // fixme: hides a member
95 char endChar = *endTag;
96 int length = strlen( endTag );
97
98 // Inner loop of text parsing.
99 while ( *p ) {
100 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
101 Set( start, p, strFlags );
102 return p + length;
103 }
104 ++p;
105 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800106 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800107}
108
109
110char* StrPair::ParseName( char* p )
111{
112 char* start = p;
113
114 start = p;
115 if ( !start || !(*start) ) {
116 return 0;
117 }
118
119 if ( !XMLUtil::IsAlpha( *p ) ) {
120 return 0;
121 }
122
123 while( *p && (
124 XMLUtil::IsAlphaNum( (unsigned char) *p )
125 || *p == '_'
126 || *p == '-'
127 || *p == '.'
128 || *p == ':' ))
129 {
130 ++p;
131 }
132
133 if ( p > start ) {
134 Set( start, p, 0 );
135 return p;
136 }
137 return 0;
138}
139
140
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800141
Lee Thomasone4422302012-01-20 17:59:50 -0800142const char* StrPair::GetStr()
143{
144 if ( flags & NEEDS_FLUSH ) {
145 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800146 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800147
Lee Thomason8ee79892012-01-25 17:44:30 -0800148 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800149 char* p = start; // the read pointer
150 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800151
152 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800153 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800154 // CR-LF pair becomes LF
155 // CR alone becomes LF
156 // LF-CR becomes LF
157 if ( *(p+1) == LF ) {
158 p += 2;
159 }
160 else {
161 ++p;
162 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800163 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800164 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800165 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800166 if ( *(p+1) == CR ) {
167 p += 2;
168 }
169 else {
170 ++p;
171 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800172 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800173 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800174 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
175 int i=0;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800176
177 // Entities handled by tinyXML2:
178 // - special entities in the entity table [in/out]
179 // - numeric character reference [in]
180 // &#20013; or &#x4e2d;
181
182 if ( *(p+1) == '#' ) {
183 char buf[10] = { 0 };
184 int len;
185 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
186 for( int i=0; i<len; ++i ) {
187 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800188 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800189 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800190 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800191 else {
192 for( i=0; i<NUM_ENTITIES; ++i ) {
193 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
194 && *(p+entities[i].length+1) == ';' )
195 {
196 // Found an entity convert;
197 *q = entities[i].value;
198 ++q;
199 p += entities[i].length + 2;
200 break;
201 }
202 }
203 if ( i == NUM_ENTITIES ) {
204 // fixme: treat as error?
205 ++p;
206 ++q;
207 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800208 }
209 }
Lee Thomasone4422302012-01-20 17:59:50 -0800210 else {
211 *q = *p;
212 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800213 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800214 }
215 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800216 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800217 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800218 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800219 }
220 return start;
221}
222
Lee Thomason2c85a712012-01-31 08:24:24 -0800223
Lee Thomasone4422302012-01-20 17:59:50 -0800224
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800225
Lee Thomason56bdd022012-02-09 18:16:58 -0800226// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800227
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800228const char* XMLUtil::ReadBOM( const char* p, bool* bom )
229{
230 *bom = false;
231 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
232 // Check for BOM:
233 if ( *(pu+0) == TIXML_UTF_LEAD_0
234 && *(pu+1) == TIXML_UTF_LEAD_1
235 && *(pu+2) == TIXML_UTF_LEAD_2 )
236 {
237 *bom = true;
238 p += 3;
239 }
240 return p;
241}
242
243
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800244void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
245{
246 const unsigned long BYTE_MASK = 0xBF;
247 const unsigned long BYTE_MARK = 0x80;
248 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
249
250 if (input < 0x80)
251 *length = 1;
252 else if ( input < 0x800 )
253 *length = 2;
254 else if ( input < 0x10000 )
255 *length = 3;
256 else if ( input < 0x200000 )
257 *length = 4;
258 else
259 { *length = 0; return; } // This code won't covert this correctly anyway.
260
261 output += *length;
262
263 // Scary scary fall throughs.
264 switch (*length)
265 {
266 case 4:
267 --output;
268 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
269 input >>= 6;
270 case 3:
271 --output;
272 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
273 input >>= 6;
274 case 2:
275 --output;
276 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
277 input >>= 6;
278 case 1:
279 --output;
280 *output = (char)(input | FIRST_BYTE_MARK[*length]);
281 }
282}
283
284
285const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
286{
287 // Presume an entity, and pull it out.
288 *length = 0;
289
290 if ( *(p+1) == '#' && *(p+2) )
291 {
292 unsigned long ucs = 0;
293 ptrdiff_t delta = 0;
294 unsigned mult = 1;
295
296 if ( *(p+2) == 'x' )
297 {
298 // Hexadecimal.
299 if ( !*(p+3) ) return 0;
300
301 const char* q = p+3;
302 q = strchr( q, ';' );
303
304 if ( !q || !*q ) return 0;
305
306 delta = q-p;
307 --q;
308
309 while ( *q != 'x' )
310 {
311 if ( *q >= '0' && *q <= '9' )
312 ucs += mult * (*q - '0');
313 else if ( *q >= 'a' && *q <= 'f' )
314 ucs += mult * (*q - 'a' + 10);
315 else if ( *q >= 'A' && *q <= 'F' )
316 ucs += mult * (*q - 'A' + 10 );
317 else
318 return 0;
319 mult *= 16;
320 --q;
321 }
322 }
323 else
324 {
325 // Decimal.
326 if ( !*(p+2) ) return 0;
327
328 const char* q = p+2;
329 q = strchr( q, ';' );
330
331 if ( !q || !*q ) return 0;
332
333 delta = q-p;
334 --q;
335
336 while ( *q != '#' )
337 {
338 if ( *q >= '0' && *q <= '9' )
339 ucs += mult * (*q - '0');
340 else
341 return 0;
342 mult *= 10;
343 --q;
344 }
345 }
346 // convert the UCS to UTF-8
347 ConvertUTF32ToUTF8( ucs, value, length );
348 return p + delta + 1;
349 }
350 return p+1;
351}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800352
353
Lee Thomasond1983222012-02-06 08:41:24 -0800354char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800355{
356 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800357 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800358 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800359 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800360 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800361 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800362 }
363
364 // What is this thing?
365 // - Elements start with a letter or underscore, but xml is reserved.
366 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800367 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800368 // - Everthing else is unknown to tinyxml.
369 //
370
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800371 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800372 static const char* commentHeader = { "<!--" };
373 static const char* dtdHeader = { "<!" };
374 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800375 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800376
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800377 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800378 static const int commentHeaderLen = 4;
379 static const int dtdHeaderLen = 2;
380 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800381 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800382
Lee Thomason50f97b22012-02-11 16:33:40 -0800383 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
384 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
385
386 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
387 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
388 returnNode->memPool = &commentPool;
389 p += xmlHeaderLen;
390 }
391 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800392 returnNode = new (commentPool.Alloc()) XMLComment( this );
393 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800394 p += commentHeaderLen;
395 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800396 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
397 XMLText* text = new (textPool.Alloc()) XMLText( this );
398 returnNode = text;
399 returnNode->memPool = &textPool;
400 p += cdataHeaderLen;
401 text->SetCData( true );
402 }
403 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
404 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
405 returnNode->memPool = &commentPool;
406 p += dtdHeaderLen;
407 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800408 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800409 returnNode = new (elementPool.Alloc()) XMLElement( this );
410 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800411 p += elementHeaderLen;
412 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800413 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800414 returnNode = new (textPool.Alloc()) XMLText( this );
415 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800416 p = start; // Back it up, all the text counts.
417 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800418
419 *node = returnNode;
420 return p;
421}
422
423
Lee Thomason751da522012-02-10 08:50:51 -0800424bool XMLDocument::Accept( XMLVisitor* visitor ) const
425{
426 if ( visitor->VisitEnter( *this ) )
427 {
428 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
429 {
430 if ( !node->Accept( visitor ) )
431 break;
432 }
433 }
434 return visitor->VisitExit( *this );
435}
Lee Thomason56bdd022012-02-09 18:16:58 -0800436
437
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800438// --------- XMLNode ----------- //
439
440XMLNode::XMLNode( XMLDocument* doc ) :
441 document( doc ),
442 parent( 0 ),
443 firstChild( 0 ), lastChild( 0 ),
444 prev( 0 ), next( 0 )
445{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800446}
447
448
449XMLNode::~XMLNode()
450{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800451 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800452 if ( parent ) {
453 parent->Unlink( this );
454 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800455}
456
457
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800458void XMLNode::SetValue( const char* str, bool staticMem )
459{
460 if ( staticMem )
461 value.SetInternedStr( str );
462 else
463 value.SetStr( str );
464}
465
466
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800467void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800468{
Lee Thomasond923c672012-01-23 08:44:25 -0800469 while( firstChild ) {
470 XMLNode* node = firstChild;
471 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800472
Lee Thomason43f59302012-02-06 18:18:11 -0800473 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800474 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800475 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800476}
477
478
479void XMLNode::Unlink( XMLNode* child )
480{
481 TIXMLASSERT( child->parent == this );
482 if ( child == firstChild )
483 firstChild = firstChild->next;
484 if ( child == lastChild )
485 lastChild = lastChild->prev;
486
487 if ( child->prev ) {
488 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800489 }
Lee Thomasond923c672012-01-23 08:44:25 -0800490 if ( child->next ) {
491 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800492 }
Lee Thomasond923c672012-01-23 08:44:25 -0800493 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494}
495
496
U-Stream\Leeae25a442012-02-17 17:48:16 -0800497void XMLNode::DeleteChild( XMLNode* node )
498{
499 TIXMLASSERT( node->parent == this );
500 DELETE_NODE( node );
501}
502
503
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800504XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
505{
506 if ( lastChild ) {
507 TIXMLASSERT( firstChild );
508 TIXMLASSERT( lastChild->next == 0 );
509 lastChild->next = addThis;
510 addThis->prev = lastChild;
511 lastChild = addThis;
512
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800513 addThis->next = 0;
514 }
515 else {
516 TIXMLASSERT( firstChild == 0 );
517 firstChild = lastChild = addThis;
518
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519 addThis->prev = 0;
520 addThis->next = 0;
521 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800522 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800523 return addThis;
524}
525
526
Lee Thomason1ff38e02012-02-14 18:18:16 -0800527XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
528{
529 if ( firstChild ) {
530 TIXMLASSERT( lastChild );
531 TIXMLASSERT( firstChild->prev == 0 );
532
533 firstChild->prev = addThis;
534 addThis->next = firstChild;
535 firstChild = addThis;
536
Lee Thomason1ff38e02012-02-14 18:18:16 -0800537 addThis->prev = 0;
538 }
539 else {
540 TIXMLASSERT( lastChild == 0 );
541 firstChild = lastChild = addThis;
542
Lee Thomason1ff38e02012-02-14 18:18:16 -0800543 addThis->prev = 0;
544 addThis->next = 0;
545 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800546 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800547 return addThis;
548}
549
550
551XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
552{
553 TIXMLASSERT( afterThis->parent == this );
554 if ( afterThis->parent != this )
555 return 0;
556
557 if ( afterThis->next == 0 ) {
558 // The last node or the only node.
559 return InsertEndChild( addThis );
560 }
561 addThis->prev = afterThis;
562 addThis->next = afterThis->next;
563 afterThis->next->prev = addThis;
564 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800565 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800566 return addThis;
567}
568
569
570
571
Lee Thomason56bdd022012-02-09 18:16:58 -0800572const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800573{
574 for( XMLNode* node=firstChild; node; node=node->next ) {
575 XMLElement* element = node->ToElement();
576 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800577 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800578 return element;
579 }
580 }
581 }
582 return 0;
583}
584
585
Lee Thomason56bdd022012-02-09 18:16:58 -0800586const XMLElement* XMLNode::LastChildElement( const char* value ) const
587{
588 for( XMLNode* node=lastChild; node; node=node->prev ) {
589 XMLElement* element = node->ToElement();
590 if ( element ) {
591 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
592 return element;
593 }
594 }
595 }
596 return 0;
597}
598
599
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800600char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800601{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800602 // This is a recursive method, but thinking about it "at the current level"
603 // it is a pretty simple flat list:
604 // <foo/>
605 // <!-- comment -->
606 //
607 // With a special case:
608 // <foo>
609 // </foo>
610 // <!-- comment -->
611 //
612 // Where the closing element (/foo) *must* be the next thing after the opening
613 // element, and the names must match. BUT the tricky bit is that the closing
614 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800615 //
616 // 'endTag' is the end tag for this node, it is returned by a call to a child.
617 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800618
Lee Thomason67d61312012-01-24 16:01:51 -0800619 while( p && *p ) {
620 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800621
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800622 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800623 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800624 break;
625 }
626
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800627 StrPair endTag;
628 p = node->ParseDeep( p, &endTag );
629 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800630 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800631 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800632 if ( !document->Error() ) {
633 document->SetError( ERROR_PARSING, 0, 0 );
634 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800635 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800636 }
637
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800638 // We read the end tag. Return it to the parent.
639 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
640 if ( parentEnd ) {
641 *parentEnd = ((XMLElement*)node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800642 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800643 DELETE_NODE( node );
644 return p;
645 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800646
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800647 // Handle an end tag returned to this level.
648 // And handle a bunch of annoying errors.
649 XMLElement* ele = node->ToElement();
650 if ( ele ) {
651 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
652 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
653 p = 0;
654 }
655 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
656 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
657 p = 0;
658 }
659 else if ( !endTag.Empty() ) {
660 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800661 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
662 p = 0;
663 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800664 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800665 }
666 if ( p == 0 ) {
667 DELETE_NODE( node );
668 node = 0;
669 }
670 if ( node ) {
671 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800672 }
673 }
674 return 0;
675}
676
Lee Thomason5492a1c2012-01-23 15:32:10 -0800677// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800678char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800679{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800680 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800681 if ( this->CData() ) {
682 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800683 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800684 document->SetError( ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800685 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800686 return p;
687 }
688 else {
689 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800690 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800691 document->SetError( ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800692 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800693 if ( p && *p ) {
694 return p-1;
695 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800696 }
697 return 0;
698}
699
700
Lee Thomason56bdd022012-02-09 18:16:58 -0800701bool XMLText::Accept( XMLVisitor* visitor ) const
702{
703 return visitor->Visit( *this );
704}
705
706
Lee Thomason3f57d272012-01-11 15:30:03 -0800707// --------- XMLComment ---------- //
708
Lee Thomasone4422302012-01-20 17:59:50 -0800709XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800710{
711}
712
713
Lee Thomasonce0763e2012-01-11 15:43:54 -0800714XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800715{
Lee Thomasond923c672012-01-23 08:44:25 -0800716 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800717}
718
719
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800720char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800721{
722 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800723 const char* start = p;
724 p = value.ParseText( p, "-->", StrPair::COMMENT );
725 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800726 document->SetError( ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800727 }
728 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800729}
730
731
Lee Thomason751da522012-02-10 08:50:51 -0800732bool XMLComment::Accept( XMLVisitor* visitor ) const
733{
734 return visitor->Visit( *this );
735}
Lee Thomason56bdd022012-02-09 18:16:58 -0800736
737
Lee Thomason50f97b22012-02-11 16:33:40 -0800738// --------- XMLDeclaration ---------- //
739
740XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
741{
742}
743
744
745XMLDeclaration::~XMLDeclaration()
746{
747 //printf( "~XMLDeclaration\n" );
748}
749
750
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800751char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800752{
753 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800754 const char* start = p;
755 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
756 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800757 document->SetError( ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800758 }
759 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800760}
761
762
763bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
764{
765 return visitor->Visit( *this );
766}
767
768// --------- XMLUnknown ---------- //
769
770XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
771{
772}
773
774
775XMLUnknown::~XMLUnknown()
776{
777}
778
779
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800780char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800781{
782 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800783 const char* start = p;
784
785 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
786 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800787 document->SetError( ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800788 }
789 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800790}
791
792
793bool XMLUnknown::Accept( XMLVisitor* visitor ) const
794{
795 return visitor->Visit( *this );
796}
797
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800798// --------- XMLAttribute ---------- //
799char* XMLAttribute::ParseDeep( char* p )
800{
Lee Thomason56bdd022012-02-09 18:16:58 -0800801 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800802 if ( !p || !*p ) return 0;
803
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800804 char endTag[2] = { *p, 0 };
805 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800806 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800807 //if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800808 return p;
809}
810
811
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800812void XMLAttribute::SetName( const char* n )
813{
814 name.SetStr( n );
815}
816
817
Lee Thomason1ff38e02012-02-14 18:18:16 -0800818int XMLAttribute::QueryIntAttribute( int* value ) const
819{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800820 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800821 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800822 return WRONG_ATTRIBUTE_TYPE;
823}
824
825
826int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
827{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800828 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800829 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800830 return WRONG_ATTRIBUTE_TYPE;
831}
832
833
834int XMLAttribute::QueryBoolAttribute( bool* value ) const
835{
836 int ival = -1;
837 QueryIntAttribute( &ival );
838
839 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
840 *value = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800841 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800842 }
843 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
844 *value = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800845 return XML_NO_ERROR;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800846 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847 return WRONG_ATTRIBUTE_TYPE;
848}
849
850
851int XMLAttribute::QueryDoubleAttribute( double* value ) const
852{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800853 if ( TIXML_SSCANF( Value(), "%lf", 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::QueryFloatAttribute( float* value ) const
860{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800861 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800862 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863 return WRONG_ATTRIBUTE_TYPE;
864}
865
866
867void XMLAttribute::SetAttribute( const char* v )
868{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800869 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870}
871
872
Lee Thomason1ff38e02012-02-14 18:18:16 -0800873void XMLAttribute::SetAttribute( int v )
874{
875 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800876 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
877 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800879
880
881void XMLAttribute::SetAttribute( unsigned v )
882{
883 char buf[BUF_SIZE];
884 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
885 value.SetStr( buf );
886}
887
888
889void XMLAttribute::SetAttribute( bool v )
890{
891 char buf[BUF_SIZE];
892 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
893 value.SetStr( buf );
894}
895
896void XMLAttribute::SetAttribute( double v )
897{
898 char buf[BUF_SIZE];
899 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
900 value.SetStr( buf );
901}
902
903void XMLAttribute::SetAttribute( float v )
904{
905 char buf[BUF_SIZE];
906 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
907 value.SetStr( buf );
908}
909
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800910
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800911// --------- XMLElement ---------- //
912XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800913 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800914 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800915{
916}
917
918
919XMLElement::~XMLElement()
920{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800921 while( rootAttribute ) {
922 XMLAttribute* next = rootAttribute->next;
923 DELETE_ATTRIBUTE( rootAttribute );
924 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800925 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800926}
927
928
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800929XMLAttribute* XMLElement::FindAttribute( const char* name )
930{
931 XMLAttribute* a = 0;
932 for( a=rootAttribute; a; a = a->next ) {
933 if ( XMLUtil::StringEqual( a->Name(), name ) )
934 return a;
935 }
936 return 0;
937}
938
939
940const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
941{
942 XMLAttribute* a = 0;
943 for( a=rootAttribute; a; a = a->next ) {
944 if ( XMLUtil::StringEqual( a->Name(), name ) )
945 return a;
946 }
947 return 0;
948}
949
950
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800951const char* XMLElement::GetText() const
952{
953 if ( FirstChild() && FirstChild()->ToText() ) {
954 return FirstChild()->ToText()->Value();
955 }
956 return 0;
957}
958
959
960
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800961XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
962{
963 XMLAttribute* attrib = FindAttribute( name );
964 if ( !attrib ) {
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800965 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800966 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800967 LinkAttribute( attrib );
968 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800969 }
970 return attrib;
971}
972
973
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800974void XMLElement::LinkAttribute( XMLAttribute* attrib )
975{
976 if ( rootAttribute ) {
977 XMLAttribute* end = rootAttribute;
978 while ( end->next )
979 end = end->next;
980 end->next = attrib;
981 }
982 else {
983 rootAttribute = attrib;
984 }
985}
986
987
U-Stream\Leeae25a442012-02-17 17:48:16 -0800988void XMLElement::DeleteAttribute( const char* name )
989{
990 XMLAttribute* prev = 0;
991 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
992 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
993 if ( prev ) {
994 prev->next = a->next;
995 }
996 else {
997 rootAttribute = a->next;
998 }
999 DELETE_ATTRIBUTE( a );
1000 break;
1001 }
1002 prev = a;
1003 }
1004}
1005
1006
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001008{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001009 const char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001010
1011 // Read the attributes.
1012 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001013 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001014 if ( !p || !(*p) ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001015 document->SetError( ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001016 return 0;
1017 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001018
1019 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001020 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001021 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
1022 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001023
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001024 p = attrib->ParseDeep( p );
Lee Thomasond6277762012-02-22 16:00:12 -08001025 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001026 DELETE_ATTRIBUTE( attrib );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001027 document->SetError( ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001028 return 0;
1029 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001030 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001031 }
Lee Thomasone4422302012-01-20 17:59:50 -08001032 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001033 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001034 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001035 return p+2; // done; sealed element.
1036 }
Lee Thomasone4422302012-01-20 17:59:50 -08001037 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001038 else if ( *p == '>' ) {
1039 ++p;
1040 break;
1041 }
Lee Thomasone4422302012-01-20 17:59:50 -08001042 else {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001043 document->SetError( ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001044 return 0;
1045 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001046 }
Lee Thomason67d61312012-01-24 16:01:51 -08001047 return p;
1048}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001049
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001050
Lee Thomason67d61312012-01-24 16:01:51 -08001051//
1052// <ele></ele>
1053// <ele>foo<b>bar</b></ele>
1054//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001055char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001056{
1057 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001058 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001059 if ( !p ) return 0;
1060 const char* start = p;
1061
1062 // The closing element is the </element> form. It is
1063 // parsed just like a regular element then deleted from
1064 // the DOM.
1065 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001066 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001067 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001068 }
Lee Thomason67d61312012-01-24 16:01:51 -08001069
Lee Thomason56bdd022012-02-09 18:16:58 -08001070 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001071 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001072
1073 bool elementClosed=false;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001074 p = ParseAttributes( p );
1075 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001076 return p;
1077
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001078 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001079 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001080}
1081
1082
Lee Thomason751da522012-02-10 08:50:51 -08001083bool XMLElement::Accept( XMLVisitor* visitor ) const
1084{
1085 if ( visitor->VisitEnter( *this, rootAttribute ) )
1086 {
1087 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1088 {
1089 if ( !node->Accept( visitor ) )
1090 break;
1091 }
1092 }
1093 return visitor->VisitExit( *this );
1094
1095}
Lee Thomason56bdd022012-02-09 18:16:58 -08001096
Lee Thomason3f57d272012-01-11 15:30:03 -08001097// --------- XMLDocument ----------- //
Lee Thomason67d61312012-01-24 16:01:51 -08001098XMLDocument::XMLDocument() :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001099 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001100 writeBOM( false ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001101 charBuffer( 0 )
1102{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001103 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001104}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001105
1106
Lee Thomason3f57d272012-01-11 15:30:03 -08001107XMLDocument::~XMLDocument()
1108{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001109 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001110 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001111
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001112#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001113 textPool.Trace( "text" );
1114 elementPool.Trace( "element" );
1115 commentPool.Trace( "comment" );
1116 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001117#endif
1118
Lee Thomason455c9d42012-02-06 09:14:14 -08001119 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1120 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1121 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1122 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001123}
1124
1125
Lee Thomason18d68bd2012-01-26 18:17:26 -08001126void XMLDocument::InitDocument()
1127{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001128 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001129 errorStr1 = 0;
1130 errorStr2 = 0;
1131
1132 delete [] charBuffer;
1133 charBuffer = 0;
1134
1135}
1136
Lee Thomason3f57d272012-01-11 15:30:03 -08001137
Lee Thomason2c85a712012-01-31 08:24:24 -08001138XMLElement* XMLDocument::NewElement( const char* name )
1139{
Lee Thomasond1983222012-02-06 08:41:24 -08001140 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1141 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001142 ele->SetName( name );
1143 return ele;
1144}
1145
1146
Lee Thomason1ff38e02012-02-14 18:18:16 -08001147XMLComment* XMLDocument::NewComment( const char* str )
1148{
1149 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1150 comment->memPool = &commentPool;
1151 comment->SetValue( str );
1152 return comment;
1153}
1154
1155
1156XMLText* XMLDocument::NewText( const char* str )
1157{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001158 XMLText* text = new (textPool.Alloc()) XMLText( this );
1159 text->memPool = &textPool;
1160 text->SetValue( str );
1161 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162}
1163
1164
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001165int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001166{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001167 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001168 InitDocument();
1169
1170 FILE* fp = fopen( filename, "rb" );
1171 if ( !fp ) {
1172 SetError( ERROR_FILE_NOT_FOUND, filename, 0 );
1173 return errorID;
1174 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001175 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001176 fclose( fp );
1177 return errorID;
1178}
1179
1180
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001181int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001182{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001183 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001184 InitDocument();
1185
1186 fseek( fp, 0, SEEK_END );
1187 unsigned size = ftell( fp );
1188 fseek( fp, 0, SEEK_SET );
1189
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001190 if ( size == 0 ) {
1191 return errorID;
1192 }
1193
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001194 charBuffer = new char[size+1];
1195 fread( charBuffer, size, 1, fp );
1196 charBuffer[size] = 0;
1197
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001198 const char* p = charBuffer;
1199 p = XMLUtil::SkipWhiteSpace( p );
1200 p = XMLUtil::ReadBOM( p, &writeBOM );
1201 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001202 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1203 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001204 }
1205
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001206 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001207 return errorID;
1208}
1209
1210
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001211void XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001212{
1213 FILE* fp = fopen( filename, "w" );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001214 XMLPrinter stream( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001215 Print( &stream );
1216 fclose( fp );
1217}
1218
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219
Lee Thomason7c913cd2012-01-26 18:32:34 -08001220int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001221{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001222 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001223 InitDocument();
1224
1225 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001226 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1227 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001228 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001229 p = XMLUtil::SkipWhiteSpace( p );
1230 p = XMLUtil::ReadBOM( p, &writeBOM );
1231 if ( !p || !*p ) {
Lee Thomasond6277762012-02-22 16:00:12 -08001232 SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
1233 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001234 }
1235
Lee Thomason18d68bd2012-01-26 18:17:26 -08001236 size_t len = strlen( p );
1237 charBuffer = new char[ len+1 ];
1238 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001239
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001240
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001241 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001242 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001243}
1244
1245
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001246void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001247{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001248 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001249 if ( !streamer )
1250 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001251 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001252}
1253
1254
Lee Thomason67d61312012-01-24 16:01:51 -08001255void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1256{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001257 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001258 errorStr1 = str1;
1259 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001260}
1261
Lee Thomason5cae8972012-01-24 18:03:07 -08001262
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001263void XMLDocument::PrintError() const
1264{
1265 if ( errorID ) {
1266 char buf1[20] = { 0 };
1267 char buf2[20] = { 0 };
1268
1269 if ( errorStr1 ) {
1270 strncpy( buf1, errorStr1, 20 );
1271 buf1[19] = 0;
1272 }
1273 if ( errorStr2 ) {
1274 strncpy( buf2, errorStr2, 20 );
1275 buf2[19] = 0;
1276 }
1277
1278 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1279 errorID, buf1, buf2 );
1280 }
1281}
1282
1283
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001284XMLPrinter::XMLPrinter( FILE* file ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001285 elementJustOpened( false ),
1286 firstElement( true ),
1287 fp( file ),
1288 depth( 0 ),
1289 textDepth( -1 )
Lee Thomason5cae8972012-01-24 18:03:07 -08001290{
Lee Thomason857b8682012-01-25 17:50:25 -08001291 for( int i=0; i<ENTITY_RANGE; ++i ) {
1292 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001293 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001294 }
1295 for( int i=0; i<NUM_ENTITIES; ++i ) {
1296 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1297 if ( entities[i].value < ENTITY_RANGE ) {
1298 entityFlag[ entities[i].value ] = true;
1299 }
1300 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301 restrictedEntityFlag['&'] = true;
1302 restrictedEntityFlag['<'] = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001303 restrictedEntityFlag['>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001304 buffer.Push( 0 );
1305}
1306
1307
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001308void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001309{
1310 va_list va;
1311 va_start( va, format );
1312
1313 if ( fp ) {
1314 vfprintf( fp, format, va );
1315 }
1316 else {
1317 // This seems brutally complex. Haven't figured out a better
1318 // way on windows.
1319 #ifdef _MSC_VER
1320 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001321 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001322 while ( len < 0 ) {
1323 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );
1324 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001325 accumulator.PushArr( expand );
1326 expand *= 3/2;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001327 }
1328 }
1329 char* p = buffer.PushArr( len ) - 1;
1330 memcpy( p, accumulator.Mem(), len+1 );
1331 #else
1332 int len = vsnprintf( 0, 0, format, va );
1333 char* p = buffer.PushArr( len ) - 1;
1334 vsprintf_s( p, len+1, format, va );
1335 #endif
1336 }
1337 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001338}
1339
1340
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001341void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001342{
1343 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001344 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001345 }
1346}
1347
1348
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001349void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001350{
Lee Thomason951d8832012-01-26 08:47:06 -08001351 // Look for runs of bytes between entities to print.
1352 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001353 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001354
Lee Thomason951d8832012-01-26 08:47:06 -08001355 while ( *q ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001356 // Remember, char is sometimes signed. (How many times has that bitten me?)
1357 if ( *q > 0 && *q < ENTITY_RANGE ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001358 // Check for entities. If one is found, flush
1359 // the stream up until the entity, write the
1360 // entity, and keep looking.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001361 if ( flag[*q] ) {
Lee Thomason951d8832012-01-26 08:47:06 -08001362 while ( p < q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001363 Print( "%c", *p );
Lee Thomason951d8832012-01-26 08:47:06 -08001364 ++p;
1365 }
1366 for( int i=0; i<NUM_ENTITIES; ++i ) {
1367 if ( entities[i].value == *q ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001368 Print( "&%s;", entities[i].pattern );
Lee Thomason951d8832012-01-26 08:47:06 -08001369 break;
1370 }
1371 }
1372 ++p;
1373 }
1374 }
1375 ++q;
1376 }
1377 // Flush the remaining string. This will be the entire
1378 // string if an entity wasn't found.
1379 if ( q-p > 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001380 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001381 }
Lee Thomason857b8682012-01-25 17:50:25 -08001382}
1383
U-Stream\Leeae25a442012-02-17 17:48:16 -08001384
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001385void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001386{
1387 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1388 if ( writeBOM ) {
1389 Print( "%s", bom );
1390 }
1391 if ( writeDec ) {
1392 PushDeclaration( "xml version=\"1.0\"" );
1393 }
1394}
1395
1396
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001397void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001398{
1399 if ( elementJustOpened ) {
1400 SealElement();
1401 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001402 stack.Push( name );
1403
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001404 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001405 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001406 PrintSpace( depth );
1407 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001408
U-Stream\Leeae25a442012-02-17 17:48:16 -08001409 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001410 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001411 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001412 ++depth;
1413}
1414
1415
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001416void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001417{
1418 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001419 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001420 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001421 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001422}
1423
1424
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001425void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001426{
1427 --depth;
1428 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001429
1430 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001431 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001432 }
1433 else {
Lee Thomason56bdd022012-02-09 18:16:58 -08001434 if ( textDepth < 0 ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001435 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001436 PrintSpace( depth );
1437 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001438 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001439 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001440
1441 if ( textDepth == depth )
1442 textDepth = -1;
1443 if ( depth == 0 )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001444 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001445 elementJustOpened = false;
1446}
1447
1448
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001449void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001450{
1451 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001452 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001453}
1454
1455
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001456void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001457{
Lee Thomason56bdd022012-02-09 18:16:58 -08001458 textDepth = depth-1;
1459
Lee Thomason5cae8972012-01-24 18:03:07 -08001460 if ( elementJustOpened ) {
1461 SealElement();
1462 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001463 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001464 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001465 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001466 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001467 }
1468 else {
1469 PrintString( text, true );
1470 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001471}
1472
1473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001474void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001475{
1476 if ( elementJustOpened ) {
1477 SealElement();
1478 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001479 if ( textDepth < 0 && !firstElement ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001480 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001481 PrintSpace( depth );
1482 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001483 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001484 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001485}
Lee Thomason751da522012-02-10 08:50:51 -08001486
1487
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001488void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001489{
1490 if ( elementJustOpened ) {
1491 SealElement();
1492 }
1493 if ( textDepth < 0 && !firstElement) {
1494 Print( "\n" );
1495 PrintSpace( depth );
1496 }
1497 firstElement = false;
1498 Print( "<?%s?>", value );
1499}
1500
1501
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001502void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001503{
1504 if ( elementJustOpened ) {
1505 SealElement();
1506 }
1507 if ( textDepth < 0 && !firstElement ) {
1508 Print( "\n" );
1509 PrintSpace( depth );
1510 }
1511 firstElement = false;
1512 Print( "<!%s>", value );
1513}
1514
1515
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001516bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001517{
1518 if ( doc.HasBOM() ) {
1519 PushHeader( true, false );
1520 }
1521 return true;
1522}
1523
1524
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001525bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001526{
1527 OpenElement( element.Name() );
1528 while ( attribute ) {
1529 PushAttribute( attribute->Name(), attribute->Value() );
1530 attribute = attribute->Next();
1531 }
1532 return true;
1533}
1534
1535
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001536bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08001537{
1538 CloseElement();
1539 return true;
1540}
1541
1542
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001543bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001544{
Lee Thomasond6277762012-02-22 16:00:12 -08001545 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001546 return true;
1547}
1548
1549
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001550bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08001551{
1552 PushComment( comment.Value() );
1553 return true;
1554}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001555
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001556bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001557{
1558 PushDeclaration( declaration.Value() );
1559 return true;
1560}
1561
1562
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001563bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001564{
1565 PushUnknown( unknown.Value() );
1566 return true;
1567}
1568
1569