blob: 2dab5011d5728aff2e0dac966ed88a9c2a4b3be4 [file] [log] [blame]
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -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*/
23
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 Thomasond1983222012-02-06 08:41:24 -080030#include <new.h>
U-Stream\Leeae25a442012-02-17 17:48:16 -080031#include <stdarg.h>
Lee Thomasond1983222012-02-06 08:41:24 -080032
33//#pragma warning ( disable : 4291 )
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
35using namespace tinyxml2;
36
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080038static const char LF = LINE_FEED;
39static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
40static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080041static const char SINGLE_QUOTE = '\'';
42static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080043
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080044// Bunch of unicode info at:
45// http://www.unicode.org/faq/utf_bom.html
46// ef bb bf (Microsoft "lead bytes") - designates UTF-8
47
48static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
49static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
50static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080051
52
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080053#define DELETE_NODE( node ) { \
54 if ( node ) { \
55 MemPool* pool = node->memPool; \
56 node->~XMLNode(); \
57 pool->Free( node ); \
58 } \
59}
60#define DELETE_ATTRIBUTE( attrib ) { \
61 if ( attrib ) { \
62 MemPool* pool = attrib->memPool; \
63 attrib->~XMLAttribute(); \
64 pool->Free( attrib ); \
65 } \
66}
Lee Thomason43f59302012-02-06 18:18:11 -080067
Lee Thomason8ee79892012-01-25 17:44:30 -080068struct Entity {
69 const char* pattern;
70 int length;
71 char value;
72};
73
74static const int NUM_ENTITIES = 5;
75static const Entity entities[NUM_ENTITIES] =
76{
Lee Thomason18d68bd2012-01-26 18:17:26 -080077 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080078 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080079 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080080 { "lt", 2, '<' },
81 { "gt", 2, '>' }
82};
83
Lee Thomasonfde6a752012-01-14 18:08:12 -080084
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085StrPair::~StrPair()
86{
87 Reset();
88}
89
90
91void StrPair::Reset()
92{
93 if ( flags & NEEDS_DELETE ) {
94 delete [] start;
95 }
96 flags = 0;
97 start = 0;
98 end = 0;
99}
100
101
102void StrPair::SetStr( const char* str, int flags )
103{
104 Reset();
105 size_t len = strlen( str );
106 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800107 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108 end = start + len;
109 this->flags = flags | NEEDS_DELETE;
110}
111
112
113char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
114{
115 TIXMLASSERT( endTag && *endTag );
116
117 char* start = p; // fixme: hides a member
118 char endChar = *endTag;
119 int length = strlen( endTag );
120
121 // Inner loop of text parsing.
122 while ( *p ) {
123 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
124 Set( start, p, strFlags );
125 return p + length;
126 }
127 ++p;
128 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800129 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800130}
131
132
133char* StrPair::ParseName( char* p )
134{
135 char* start = p;
136
137 start = p;
138 if ( !start || !(*start) ) {
139 return 0;
140 }
141
142 if ( !XMLUtil::IsAlpha( *p ) ) {
143 return 0;
144 }
145
146 while( *p && (
147 XMLUtil::IsAlphaNum( (unsigned char) *p )
148 || *p == '_'
149 || *p == '-'
150 || *p == '.'
151 || *p == ':' ))
152 {
153 ++p;
154 }
155
156 if ( p > start ) {
157 Set( start, p, 0 );
158 return p;
159 }
160 return 0;
161}
162
163
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800164
Lee Thomasone4422302012-01-20 17:59:50 -0800165const char* StrPair::GetStr()
166{
167 if ( flags & NEEDS_FLUSH ) {
168 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800169 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800170
Lee Thomason8ee79892012-01-25 17:44:30 -0800171 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800172 char* p = start; // the read pointer
173 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800174
175 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800176 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800177 // CR-LF pair becomes LF
178 // CR alone becomes LF
179 // LF-CR becomes LF
180 if ( *(p+1) == LF ) {
181 p += 2;
182 }
183 else {
184 ++p;
185 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800186 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800187 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800188 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800189 if ( *(p+1) == CR ) {
190 p += 2;
191 }
192 else {
193 ++p;
194 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800195 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800196 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800197 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
198 int i=0;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800199
200 // Entities handled by tinyXML2:
201 // - special entities in the entity table [in/out]
202 // - numeric character reference [in]
203 // &#20013; or &#x4e2d;
204
205 if ( *(p+1) == '#' ) {
206 char buf[10] = { 0 };
207 int len;
208 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
209 for( int i=0; i<len; ++i ) {
210 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800211 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800212 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800213 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800214 else {
215 for( i=0; i<NUM_ENTITIES; ++i ) {
216 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
217 && *(p+entities[i].length+1) == ';' )
218 {
219 // Found an entity convert;
220 *q = entities[i].value;
221 ++q;
222 p += entities[i].length + 2;
223 break;
224 }
225 }
226 if ( i == NUM_ENTITIES ) {
227 // fixme: treat as error?
228 ++p;
229 ++q;
230 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800231 }
232 }
Lee Thomasone4422302012-01-20 17:59:50 -0800233 else {
234 *q = *p;
235 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800236 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800237 }
238 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800239 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800240 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800241 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800242 }
243 return start;
244}
245
Lee Thomason2c85a712012-01-31 08:24:24 -0800246
Lee Thomasone4422302012-01-20 17:59:50 -0800247
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800248
Lee Thomason56bdd022012-02-09 18:16:58 -0800249// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800250
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800251const char* XMLUtil::ReadBOM( const char* p, bool* bom )
252{
253 *bom = false;
254 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
255 // Check for BOM:
256 if ( *(pu+0) == TIXML_UTF_LEAD_0
257 && *(pu+1) == TIXML_UTF_LEAD_1
258 && *(pu+2) == TIXML_UTF_LEAD_2 )
259 {
260 *bom = true;
261 p += 3;
262 }
263 return p;
264}
265
266
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800267void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
268{
269 const unsigned long BYTE_MASK = 0xBF;
270 const unsigned long BYTE_MARK = 0x80;
271 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
272
273 if (input < 0x80)
274 *length = 1;
275 else if ( input < 0x800 )
276 *length = 2;
277 else if ( input < 0x10000 )
278 *length = 3;
279 else if ( input < 0x200000 )
280 *length = 4;
281 else
282 { *length = 0; return; } // This code won't covert this correctly anyway.
283
284 output += *length;
285
286 // Scary scary fall throughs.
287 switch (*length)
288 {
289 case 4:
290 --output;
291 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
292 input >>= 6;
293 case 3:
294 --output;
295 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
296 input >>= 6;
297 case 2:
298 --output;
299 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
300 input >>= 6;
301 case 1:
302 --output;
303 *output = (char)(input | FIRST_BYTE_MARK[*length]);
304 }
305}
306
307
308const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
309{
310 // Presume an entity, and pull it out.
311 *length = 0;
312
313 if ( *(p+1) == '#' && *(p+2) )
314 {
315 unsigned long ucs = 0;
316 ptrdiff_t delta = 0;
317 unsigned mult = 1;
318
319 if ( *(p+2) == 'x' )
320 {
321 // Hexadecimal.
322 if ( !*(p+3) ) return 0;
323
324 const char* q = p+3;
325 q = strchr( q, ';' );
326
327 if ( !q || !*q ) return 0;
328
329 delta = q-p;
330 --q;
331
332 while ( *q != 'x' )
333 {
334 if ( *q >= '0' && *q <= '9' )
335 ucs += mult * (*q - '0');
336 else if ( *q >= 'a' && *q <= 'f' )
337 ucs += mult * (*q - 'a' + 10);
338 else if ( *q >= 'A' && *q <= 'F' )
339 ucs += mult * (*q - 'A' + 10 );
340 else
341 return 0;
342 mult *= 16;
343 --q;
344 }
345 }
346 else
347 {
348 // Decimal.
349 if ( !*(p+2) ) return 0;
350
351 const char* q = p+2;
352 q = strchr( q, ';' );
353
354 if ( !q || !*q ) return 0;
355
356 delta = q-p;
357 --q;
358
359 while ( *q != '#' )
360 {
361 if ( *q >= '0' && *q <= '9' )
362 ucs += mult * (*q - '0');
363 else
364 return 0;
365 mult *= 10;
366 --q;
367 }
368 }
369 // convert the UCS to UTF-8
370 ConvertUTF32ToUTF8( ucs, value, length );
371 return p + delta + 1;
372 }
373 return p+1;
374}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800375
376
Lee Thomasond1983222012-02-06 08:41:24 -0800377char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800378{
379 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800380 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800381 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800382 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800383 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800384 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800385 }
386
387 // What is this thing?
388 // - Elements start with a letter or underscore, but xml is reserved.
389 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800390 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800391 // - Everthing else is unknown to tinyxml.
392 //
393
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800394 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800395 static const char* commentHeader = { "<!--" };
396 static const char* dtdHeader = { "<!" };
397 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800398 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800399
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800400 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800401 static const int commentHeaderLen = 4;
402 static const int dtdHeaderLen = 2;
403 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800404 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800405
Lee Thomason50f97b22012-02-11 16:33:40 -0800406 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
407 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
408
409 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
410 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
411 returnNode->memPool = &commentPool;
412 p += xmlHeaderLen;
413 }
414 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800415 returnNode = new (commentPool.Alloc()) XMLComment( this );
416 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800417 p += commentHeaderLen;
418 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800419 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
420 XMLText* text = new (textPool.Alloc()) XMLText( this );
421 returnNode = text;
422 returnNode->memPool = &textPool;
423 p += cdataHeaderLen;
424 text->SetCData( true );
425 }
426 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
427 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
428 returnNode->memPool = &commentPool;
429 p += dtdHeaderLen;
430 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800431 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800432 returnNode = new (elementPool.Alloc()) XMLElement( this );
433 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800434 p += elementHeaderLen;
435 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800436 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800437 returnNode = new (textPool.Alloc()) XMLText( this );
438 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800439 p = start; // Back it up, all the text counts.
440 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800441
442 *node = returnNode;
443 return p;
444}
445
446
Lee Thomason751da522012-02-10 08:50:51 -0800447bool XMLDocument::Accept( XMLVisitor* visitor ) const
448{
449 if ( visitor->VisitEnter( *this ) )
450 {
451 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
452 {
453 if ( !node->Accept( visitor ) )
454 break;
455 }
456 }
457 return visitor->VisitExit( *this );
458}
Lee Thomason56bdd022012-02-09 18:16:58 -0800459
460
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800461// --------- XMLNode ----------- //
462
463XMLNode::XMLNode( XMLDocument* doc ) :
464 document( doc ),
465 parent( 0 ),
466 firstChild( 0 ), lastChild( 0 ),
467 prev( 0 ), next( 0 )
468{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800469}
470
471
472XMLNode::~XMLNode()
473{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800474 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800475 if ( parent ) {
476 parent->Unlink( this );
477 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800478}
479
480
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800481void XMLNode::SetValue( const char* str, bool staticMem )
482{
483 if ( staticMem )
484 value.SetInternedStr( str );
485 else
486 value.SetStr( str );
487}
488
489
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800490void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800491{
Lee Thomasond923c672012-01-23 08:44:25 -0800492 while( firstChild ) {
493 XMLNode* node = firstChild;
494 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800495
Lee Thomason43f59302012-02-06 18:18:11 -0800496 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800497 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800498 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800499}
500
501
502void XMLNode::Unlink( XMLNode* child )
503{
504 TIXMLASSERT( child->parent == this );
505 if ( child == firstChild )
506 firstChild = firstChild->next;
507 if ( child == lastChild )
508 lastChild = lastChild->prev;
509
510 if ( child->prev ) {
511 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800512 }
Lee Thomasond923c672012-01-23 08:44:25 -0800513 if ( child->next ) {
514 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800515 }
Lee Thomasond923c672012-01-23 08:44:25 -0800516 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517}
518
519
U-Stream\Leeae25a442012-02-17 17:48:16 -0800520void XMLNode::DeleteChild( XMLNode* node )
521{
522 TIXMLASSERT( node->parent == this );
523 DELETE_NODE( node );
524}
525
526
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800527XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
528{
529 if ( lastChild ) {
530 TIXMLASSERT( firstChild );
531 TIXMLASSERT( lastChild->next == 0 );
532 lastChild->next = addThis;
533 addThis->prev = lastChild;
534 lastChild = addThis;
535
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800536 addThis->next = 0;
537 }
538 else {
539 TIXMLASSERT( firstChild == 0 );
540 firstChild = lastChild = addThis;
541
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800542 addThis->prev = 0;
543 addThis->next = 0;
544 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800545 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800546 return addThis;
547}
548
549
Lee Thomason1ff38e02012-02-14 18:18:16 -0800550XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
551{
552 if ( firstChild ) {
553 TIXMLASSERT( lastChild );
554 TIXMLASSERT( firstChild->prev == 0 );
555
556 firstChild->prev = addThis;
557 addThis->next = firstChild;
558 firstChild = addThis;
559
Lee Thomason1ff38e02012-02-14 18:18:16 -0800560 addThis->prev = 0;
561 }
562 else {
563 TIXMLASSERT( lastChild == 0 );
564 firstChild = lastChild = addThis;
565
Lee Thomason1ff38e02012-02-14 18:18:16 -0800566 addThis->prev = 0;
567 addThis->next = 0;
568 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800569 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800570 return addThis;
571}
572
573
574XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
575{
576 TIXMLASSERT( afterThis->parent == this );
577 if ( afterThis->parent != this )
578 return 0;
579
580 if ( afterThis->next == 0 ) {
581 // The last node or the only node.
582 return InsertEndChild( addThis );
583 }
584 addThis->prev = afterThis;
585 addThis->next = afterThis->next;
586 afterThis->next->prev = addThis;
587 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800588 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800589 return addThis;
590}
591
592
593
594
Lee Thomason56bdd022012-02-09 18:16:58 -0800595const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800596{
597 for( XMLNode* node=firstChild; node; node=node->next ) {
598 XMLElement* element = node->ToElement();
599 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800600 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800601 return element;
602 }
603 }
604 }
605 return 0;
606}
607
608
Lee Thomason56bdd022012-02-09 18:16:58 -0800609const XMLElement* XMLNode::LastChildElement( const char* value ) const
610{
611 for( XMLNode* node=lastChild; node; node=node->prev ) {
612 XMLElement* element = node->ToElement();
613 if ( element ) {
614 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
615 return element;
616 }
617 }
618 }
619 return 0;
620}
621
622
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800623char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800624{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800625 // This is a recursive method, but thinking about it "at the current level"
626 // it is a pretty simple flat list:
627 // <foo/>
628 // <!-- comment -->
629 //
630 // With a special case:
631 // <foo>
632 // </foo>
633 // <!-- comment -->
634 //
635 // Where the closing element (/foo) *must* be the next thing after the opening
636 // element, and the names must match. BUT the tricky bit is that the closing
637 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800638 //
639 // 'endTag' is the end tag for this node, it is returned by a call to a child.
640 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800641
Lee Thomason67d61312012-01-24 16:01:51 -0800642 while( p && *p ) {
643 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800644
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800645 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800646 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800647 break;
648 }
649
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800650 StrPair endTag;
651 p = node->ParseDeep( p, &endTag );
652 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800653 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800654 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800655 if ( !document->Error() ) {
656 document->SetError( ERROR_PARSING, 0, 0 );
657 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800658 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800659 }
660
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800661 // We read the end tag. Return it to the parent.
662 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
663 if ( parentEnd ) {
664 *parentEnd = ((XMLElement*)node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800665 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800666 DELETE_NODE( node );
667 return p;
668 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800669
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800670 // Handle an end tag returned to this level.
671 // And handle a bunch of annoying errors.
672 XMLElement* ele = node->ToElement();
673 if ( ele ) {
674 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
675 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
676 p = 0;
677 }
678 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
679 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
680 p = 0;
681 }
682 else if ( !endTag.Empty() ) {
683 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800684 document->SetError( ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
685 p = 0;
686 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800687 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800688 }
689 if ( p == 0 ) {
690 DELETE_NODE( node );
691 node = 0;
692 }
693 if ( node ) {
694 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800695 }
696 }
697 return 0;
698}
699
Lee Thomason5492a1c2012-01-23 15:32:10 -0800700// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800701char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800702{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800703 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800704 if ( this->CData() ) {
705 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800706 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800707 document->SetError( ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800708 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800709 return p;
710 }
711 else {
712 p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800713 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800714 document->SetError( ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800715 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800716 if ( p && *p ) {
717 return p-1;
718 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800719 }
720 return 0;
721}
722
723
Lee Thomason56bdd022012-02-09 18:16:58 -0800724bool XMLText::Accept( XMLVisitor* visitor ) const
725{
726 return visitor->Visit( *this );
727}
728
729
Lee Thomason3f57d272012-01-11 15:30:03 -0800730// --------- XMLComment ---------- //
731
Lee Thomasone4422302012-01-20 17:59:50 -0800732XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800733{
734}
735
736
Lee Thomasonce0763e2012-01-11 15:43:54 -0800737XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800738{
Lee Thomasond923c672012-01-23 08:44:25 -0800739 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800740}
741
742
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800743char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800744{
745 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800746 const char* start = p;
747 p = value.ParseText( p, "-->", StrPair::COMMENT );
748 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800749 document->SetError( ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800750 }
751 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800752}
753
754
Lee Thomason751da522012-02-10 08:50:51 -0800755bool XMLComment::Accept( XMLVisitor* visitor ) const
756{
757 return visitor->Visit( *this );
758}
Lee Thomason56bdd022012-02-09 18:16:58 -0800759
760
Lee Thomason50f97b22012-02-11 16:33:40 -0800761// --------- XMLDeclaration ---------- //
762
763XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
764{
765}
766
767
768XMLDeclaration::~XMLDeclaration()
769{
770 //printf( "~XMLDeclaration\n" );
771}
772
773
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800774char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800775{
776 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800777 const char* start = p;
778 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
779 if ( p == 0 ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800780 document->SetError( ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800781 }
782 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800783}
784
785
786bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
787{
788 return visitor->Visit( *this );
789}
790
791// --------- XMLUnknown ---------- //
792
793XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
794{
795}
796
797
798XMLUnknown::~XMLUnknown()
799{
800}
801
802
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800803char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800804{
805 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800806 const char* start = p;
807
808 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
809 if ( !p ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800810 document->SetError( ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800811 }
812 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800813}
814
815
816bool XMLUnknown::Accept( XMLVisitor* visitor ) const
817{
818 return visitor->Visit( *this );
819}
820
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800821// --------- XMLAttribute ---------- //
822char* XMLAttribute::ParseDeep( char* p )
823{
Lee Thomason56bdd022012-02-09 18:16:58 -0800824 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
Lee Thomason22aead12012-01-23 13:29:35 -0800825 if ( !p || !*p ) return 0;
826
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800827 char endTag[2] = { *p, 0 };
828 ++p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800829 p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800830 //if ( value.Empty() ) return 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800831 return p;
832}
833
834
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800835void XMLAttribute::SetName( const char* n )
836{
837 name.SetStr( n );
838}
839
840
Lee Thomason1ff38e02012-02-14 18:18:16 -0800841int XMLAttribute::QueryIntAttribute( int* value ) const
842{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800843 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800844 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800845 return WRONG_ATTRIBUTE_TYPE;
846}
847
848
849int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
850{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800851 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800852 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800853 return WRONG_ATTRIBUTE_TYPE;
854}
855
856
857int XMLAttribute::QueryBoolAttribute( bool* value ) const
858{
859 int ival = -1;
860 QueryIntAttribute( &ival );
861
862 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
863 *value = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800864 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800865 }
866 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
867 *value = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800868 return XML_NO_ERROR;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800869 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870 return WRONG_ATTRIBUTE_TYPE;
871}
872
873
874int XMLAttribute::QueryDoubleAttribute( double* value ) const
875{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800876 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800877 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878 return WRONG_ATTRIBUTE_TYPE;
879}
880
881
882int XMLAttribute::QueryFloatAttribute( float* value ) const
883{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800884 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800885 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886 return WRONG_ATTRIBUTE_TYPE;
887}
888
889
890void XMLAttribute::SetAttribute( const char* v )
891{
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800892 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893}
894
895
Lee Thomason1ff38e02012-02-14 18:18:16 -0800896void XMLAttribute::SetAttribute( int v )
897{
898 char buf[BUF_SIZE];
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800899 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );
900 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800901}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800902
903
904void XMLAttribute::SetAttribute( unsigned v )
905{
906 char buf[BUF_SIZE];
907 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );
908 value.SetStr( buf );
909}
910
911
912void XMLAttribute::SetAttribute( bool v )
913{
914 char buf[BUF_SIZE];
915 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );
916 value.SetStr( buf );
917}
918
919void XMLAttribute::SetAttribute( double v )
920{
921 char buf[BUF_SIZE];
922 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
923 value.SetStr( buf );
924}
925
926void XMLAttribute::SetAttribute( float v )
927{
928 char buf[BUF_SIZE];
929 TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );
930 value.SetStr( buf );
931}
932
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800933
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800934// --------- XMLElement ---------- //
935XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800936 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800937 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800938{
939}
940
941
942XMLElement::~XMLElement()
943{
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800944 while( rootAttribute ) {
945 XMLAttribute* next = rootAttribute->next;
946 DELETE_ATTRIBUTE( rootAttribute );
947 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800948 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800949}
950
951
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800952XMLAttribute* XMLElement::FindAttribute( const char* name )
953{
954 XMLAttribute* a = 0;
955 for( a=rootAttribute; a; a = a->next ) {
956 if ( XMLUtil::StringEqual( a->Name(), name ) )
957 return a;
958 }
959 return 0;
960}
961
962
963const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
964{
965 XMLAttribute* a = 0;
966 for( a=rootAttribute; a; a = a->next ) {
967 if ( XMLUtil::StringEqual( a->Name(), name ) )
968 return a;
969 }
970 return 0;
971}
972
973
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800974const char* XMLElement::GetText() const
975{
976 if ( FirstChild() && FirstChild()->ToText() ) {
977 return FirstChild()->ToText()->Value();
978 }
979 return 0;
980}
981
982
983
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800984XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
985{
986 XMLAttribute* attrib = FindAttribute( name );
987 if ( !attrib ) {
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800988 attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800989 attrib->memPool = &document->attributePool;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800990 LinkAttribute( attrib );
991 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800992 }
993 return attrib;
994}
995
996
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800997void XMLElement::LinkAttribute( XMLAttribute* attrib )
998{
999 if ( rootAttribute ) {
1000 XMLAttribute* end = rootAttribute;
1001 while ( end->next )
1002 end = end->next;
1003 end->next = attrib;
1004 }
1005 else {
1006 rootAttribute = attrib;
1007 }
1008}
1009
1010
U-Stream\Leeae25a442012-02-17 17:48:16 -08001011void XMLElement::DeleteAttribute( const char* name )
1012{
1013 XMLAttribute* prev = 0;
1014 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1015 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1016 if ( prev ) {
1017 prev->next = a->next;
1018 }
1019 else {
1020 rootAttribute = a->next;
1021 }
1022 DELETE_ATTRIBUTE( a );
1023 break;
1024 }
1025 prev = a;
1026 }
1027}
1028
1029
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001030char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001031{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001032 const char* start = p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001033
1034 // Read the attributes.
1035 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001036 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001037 if ( !p || !(*p) ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001038 document->SetError( ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001039 return 0;
1040 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001041
1042 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001043 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001044 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
1045 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001046
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001047 p = attrib->ParseDeep( p );
Lee Thomasond6277762012-02-22 16:00:12 -08001048 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001049 DELETE_ATTRIBUTE( attrib );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001050 document->SetError( ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001051 return 0;
1052 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001053 LinkAttribute( attrib );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001054 }
Lee Thomasone4422302012-01-20 17:59:50 -08001055 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001056 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001057 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001058 return p+2; // done; sealed element.
1059 }
Lee Thomasone4422302012-01-20 17:59:50 -08001060 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001061 else if ( *p == '>' ) {
1062 ++p;
1063 break;
1064 }
Lee Thomasone4422302012-01-20 17:59:50 -08001065 else {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001066 document->SetError( ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001067 return 0;
1068 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001069 }
Lee Thomason67d61312012-01-24 16:01:51 -08001070 return p;
1071}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001072
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001073
Lee Thomason67d61312012-01-24 16:01:51 -08001074//
1075// <ele></ele>
1076// <ele>foo<b>bar</b></ele>
1077//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001078char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001079{
1080 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001081 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001082 if ( !p ) return 0;
1083 const char* start = p;
1084
1085 // The closing element is the </element> form. It is
1086 // parsed just like a regular element then deleted from
1087 // the DOM.
1088 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001090 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001091 }
Lee Thomason67d61312012-01-24 16:01:51 -08001092
Lee Thomason56bdd022012-02-09 18:16:58 -08001093 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001094 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001095
1096 bool elementClosed=false;
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 ) {
1321 entityFlag[ entities[i].value ] = true;
1322 }
1323 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001324 restrictedEntityFlag['&'] = true;
1325 restrictedEntityFlag['<'] = true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001326 restrictedEntityFlag['>'] = 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;
1357 vsprintf_s( p, len+1, format, va );
1358 #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)2a1cd272012-02-24 17:37:53 -08001559bool XMLPrinter::VisitExit( const XMLElement& element )
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