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