blob: 7ef6d44b67f43e5e18cf1e740a5cebfe6d0bc1aa [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
Lee Thomasonee87c622012-05-14 09:27:47 -070026#include <cstdio>
27#include <cstdlib>
28#include <new>
29#include <cstddef>
U-Lama\Lee560bd472011-12-28 19:42:49 -080030
31using namespace tinyxml2;
32
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
50 if ( node ) { \
51 MemPool* pool = node->memPool; \
52 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55}
56#define DELETE_ATTRIBUTE( attrib ) { \
57 if ( attrib ) { \
58 MemPool* pool = attrib->memPool; \
59 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62}
Lee Thomason43f59302012-02-06 18:18:11 -080063
Lee Thomason8ee79892012-01-25 17:44:30 -080064struct Entity {
65 const char* pattern;
66 int length;
67 char value;
68};
69
70static const int NUM_ENTITIES = 5;
71static const Entity entities[NUM_ENTITIES] =
72{
Lee Thomason18d68bd2012-01-26 18:17:26 -080073 { "quot", 4, DOUBLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080074 { "amp", 3, '&' },
Lee Thomason18d68bd2012-01-26 18:17:26 -080075 { "apos", 4, SINGLE_QUOTE },
Lee Thomason8ee79892012-01-25 17:44:30 -080076 { "lt", 2, '<' },
77 { "gt", 2, '>' }
78};
79
Lee Thomasonfde6a752012-01-14 18:08:12 -080080
Lee Thomason1a1d4a72012-02-15 09:09:25 -080081StrPair::~StrPair()
82{
83 Reset();
84}
85
86
87void StrPair::Reset()
88{
89 if ( flags & NEEDS_DELETE ) {
90 delete [] start;
91 }
92 flags = 0;
93 start = 0;
94 end = 0;
95}
96
97
98void StrPair::SetStr( const char* str, int flags )
99{
100 Reset();
101 size_t len = strlen( str );
102 start = new char[ len+1 ];
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800103 memcpy( start, str, len+1 );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104 end = start + len;
105 this->flags = flags | NEEDS_DELETE;
106}
107
108
109char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
110{
111 TIXMLASSERT( endTag && *endTag );
112
113 char* start = p; // fixme: hides a member
114 char endChar = *endTag;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200115 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800116
117 // Inner loop of text parsing.
118 while ( *p ) {
119 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
120 Set( start, p, strFlags );
121 return p + length;
122 }
123 ++p;
124 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800125 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800126}
127
128
129char* StrPair::ParseName( char* p )
130{
131 char* start = p;
132
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800133 if ( !start || !(*start) ) {
134 return 0;
135 }
136
137 if ( !XMLUtil::IsAlpha( *p ) ) {
138 return 0;
139 }
140
141 while( *p && (
142 XMLUtil::IsAlphaNum( (unsigned char) *p )
143 || *p == '_'
144 || *p == '-'
145 || *p == '.'
146 || *p == ':' ))
147 {
148 ++p;
149 }
150
151 if ( p > start ) {
152 Set( start, p, 0 );
153 return p;
154 }
155 return 0;
156}
157
158
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800159
Lee Thomasone4422302012-01-20 17:59:50 -0800160const char* StrPair::GetStr()
161{
162 if ( flags & NEEDS_FLUSH ) {
163 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800164 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800165
Lee Thomason8ee79892012-01-25 17:44:30 -0800166 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800167 char* p = start; // the read pointer
168 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800169
170 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800171 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800172 // CR-LF pair becomes LF
173 // CR alone becomes LF
174 // LF-CR becomes LF
175 if ( *(p+1) == LF ) {
176 p += 2;
177 }
178 else {
179 ++p;
180 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800181 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800182 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800183 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800184 if ( *(p+1) == CR ) {
185 p += 2;
186 }
187 else {
188 ++p;
189 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800190 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800191 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800192 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800193 // Entities handled by tinyXML2:
194 // - special entities in the entity table [in/out]
195 // - numeric character reference [in]
196 // &#20013; or &#x4e2d;
197
198 if ( *(p+1) == '#' ) {
199 char buf[10] = { 0 };
200 int len;
201 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
202 for( int i=0; i<len; ++i ) {
203 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800204 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800205 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800206 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800207 else {
PKEuSc28ba3a2012-07-16 03:08:47 -0700208 int i=0;
209 for(; i<NUM_ENTITIES; ++i ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800210 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
211 && *(p+entities[i].length+1) == ';' )
212 {
213 // Found an entity convert;
214 *q = entities[i].value;
215 ++q;
216 p += entities[i].length + 2;
217 break;
218 }
219 }
220 if ( i == NUM_ENTITIES ) {
221 // fixme: treat as error?
222 ++p;
223 ++q;
224 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800225 }
226 }
Lee Thomasone4422302012-01-20 17:59:50 -0800227 else {
228 *q = *p;
229 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800230 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800231 }
232 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800233 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800234 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800236 }
237 return start;
238}
239
Lee Thomason2c85a712012-01-31 08:24:24 -0800240
Lee Thomasone4422302012-01-20 17:59:50 -0800241
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800242
Lee Thomason56bdd022012-02-09 18:16:58 -0800243// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800244
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800245const char* XMLUtil::ReadBOM( const char* p, bool* bom )
246{
247 *bom = false;
248 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
249 // Check for BOM:
250 if ( *(pu+0) == TIXML_UTF_LEAD_0
251 && *(pu+1) == TIXML_UTF_LEAD_1
252 && *(pu+2) == TIXML_UTF_LEAD_2 )
253 {
254 *bom = true;
255 p += 3;
256 }
257 return p;
258}
259
260
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800261void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
262{
263 const unsigned long BYTE_MASK = 0xBF;
264 const unsigned long BYTE_MARK = 0x80;
265 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
266
267 if (input < 0x80)
268 *length = 1;
269 else if ( input < 0x800 )
270 *length = 2;
271 else if ( input < 0x10000 )
272 *length = 3;
273 else if ( input < 0x200000 )
274 *length = 4;
275 else
276 { *length = 0; return; } // This code won't covert this correctly anyway.
277
278 output += *length;
279
280 // Scary scary fall throughs.
281 switch (*length)
282 {
283 case 4:
284 --output;
285 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
286 input >>= 6;
287 case 3:
288 --output;
289 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
290 input >>= 6;
291 case 2:
292 --output;
293 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
294 input >>= 6;
295 case 1:
296 --output;
297 *output = (char)(input | FIRST_BYTE_MARK[*length]);
298 }
299}
300
301
302const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
303{
304 // Presume an entity, and pull it out.
305 *length = 0;
306
307 if ( *(p+1) == '#' && *(p+2) )
308 {
309 unsigned long ucs = 0;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200310 ptrdiff_t delta = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800311 unsigned mult = 1;
312
313 if ( *(p+2) == 'x' )
314 {
315 // Hexadecimal.
316 if ( !*(p+3) ) return 0;
317
318 const char* q = p+3;
319 q = strchr( q, ';' );
320
321 if ( !q || !*q ) return 0;
322
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200323 delta = q-p;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800324 --q;
325
326 while ( *q != 'x' )
327 {
328 if ( *q >= '0' && *q <= '9' )
329 ucs += mult * (*q - '0');
330 else if ( *q >= 'a' && *q <= 'f' )
331 ucs += mult * (*q - 'a' + 10);
332 else if ( *q >= 'A' && *q <= 'F' )
333 ucs += mult * (*q - 'A' + 10 );
334 else
335 return 0;
336 mult *= 16;
337 --q;
338 }
339 }
340 else
341 {
342 // Decimal.
343 if ( !*(p+2) ) return 0;
344
345 const char* q = p+2;
346 q = strchr( q, ';' );
347
348 if ( !q || !*q ) return 0;
349
350 delta = q-p;
351 --q;
352
353 while ( *q != '#' )
354 {
355 if ( *q >= '0' && *q <= '9' )
356 ucs += mult * (*q - '0');
357 else
358 return 0;
359 mult *= 10;
360 --q;
361 }
362 }
363 // convert the UCS to UTF-8
364 ConvertUTF32ToUTF8( ucs, value, length );
365 return p + delta + 1;
366 }
367 return p+1;
368}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
370
Lee Thomason21be8822012-07-15 17:27:22 -0700371void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
372{
373 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
374}
375
376
377void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
378{
379 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
380}
381
382
383void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
384{
385 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
386}
387
388
389void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
390{
391 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
392}
393
394
395void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
396{
397 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
398}
399
400
401bool XMLUtil::ToInt( const char* str, int* value )
402{
403 if ( TIXML_SSCANF( str, "%d", value ) == 1 )
404 return true;
405 return false;
406}
407
408bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
409{
410 if ( TIXML_SSCANF( str, "%u", value ) == 1 )
411 return true;
412 return false;
413}
414
415bool XMLUtil::ToBool( const char* str, bool* value )
416{
417 int ival = 0;
418 if ( ToInt( str, &ival )) {
419 *value = (ival==0) ? false : true;
420 return true;
421 }
422 if ( StringEqual( str, "true" ) ) {
423 *value = true;
424 return true;
425 }
426 else if ( StringEqual( str, "false" ) ) {
427 *value = false;
428 return true;
429 }
430 return false;
431}
432
433
434bool XMLUtil::ToFloat( const char* str, float* value )
435{
436 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
437 return true;
438 }
439 return false;
440}
441
442bool XMLUtil::ToDouble( const char* str, double* value )
443{
444 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
445 return true;
446 }
447 return false;
448}
449
450
Lee Thomasond1983222012-02-06 08:41:24 -0800451char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800452{
453 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800454 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800455 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800456 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800457 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800458 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800459 }
460
461 // What is this thing?
462 // - Elements start with a letter or underscore, but xml is reserved.
463 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800464 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800465 // - Everthing else is unknown to tinyxml.
466 //
467
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800469 static const char* commentHeader = { "<!--" };
470 static const char* dtdHeader = { "<!" };
471 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800472 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800473
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800474 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800475 static const int commentHeaderLen = 4;
476 static const int dtdHeaderLen = 2;
477 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800478 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800479
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800480#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800481#pragma warning ( push )
482#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800483#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800484 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
485 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800486#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800487#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800488#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800489 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
490 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
491 returnNode->memPool = &commentPool;
492 p += xmlHeaderLen;
493 }
494 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800495 returnNode = new (commentPool.Alloc()) XMLComment( this );
496 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800497 p += commentHeaderLen;
498 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800499 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
500 XMLText* text = new (textPool.Alloc()) XMLText( this );
501 returnNode = text;
502 returnNode->memPool = &textPool;
503 p += cdataHeaderLen;
504 text->SetCData( true );
505 }
506 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
507 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
508 returnNode->memPool = &commentPool;
509 p += dtdHeaderLen;
510 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800511 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800512 returnNode = new (elementPool.Alloc()) XMLElement( this );
513 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800514 p += elementHeaderLen;
515 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800516 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800517 returnNode = new (textPool.Alloc()) XMLText( this );
518 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800519 p = start; // Back it up, all the text counts.
520 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800521
522 *node = returnNode;
523 return p;
524}
525
526
Lee Thomason751da522012-02-10 08:50:51 -0800527bool XMLDocument::Accept( XMLVisitor* visitor ) const
528{
529 if ( visitor->VisitEnter( *this ) )
530 {
531 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
532 {
533 if ( !node->Accept( visitor ) )
534 break;
535 }
536 }
537 return visitor->VisitExit( *this );
538}
Lee Thomason56bdd022012-02-09 18:16:58 -0800539
540
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800541// --------- XMLNode ----------- //
542
543XMLNode::XMLNode( XMLDocument* doc ) :
544 document( doc ),
545 parent( 0 ),
546 firstChild( 0 ), lastChild( 0 ),
547 prev( 0 ), next( 0 )
548{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800549}
550
551
552XMLNode::~XMLNode()
553{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800554 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800555 if ( parent ) {
556 parent->Unlink( this );
557 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800558}
559
560
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800561void XMLNode::SetValue( const char* str, bool staticMem )
562{
563 if ( staticMem )
564 value.SetInternedStr( str );
565 else
566 value.SetStr( str );
567}
568
569
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800570void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800571{
Lee Thomasond923c672012-01-23 08:44:25 -0800572 while( firstChild ) {
573 XMLNode* node = firstChild;
574 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800575
Lee Thomason43f59302012-02-06 18:18:11 -0800576 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800578 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800579}
580
581
582void XMLNode::Unlink( XMLNode* child )
583{
584 TIXMLASSERT( child->parent == this );
585 if ( child == firstChild )
586 firstChild = firstChild->next;
587 if ( child == lastChild )
588 lastChild = lastChild->prev;
589
590 if ( child->prev ) {
591 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800592 }
Lee Thomasond923c672012-01-23 08:44:25 -0800593 if ( child->next ) {
594 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595 }
Lee Thomasond923c672012-01-23 08:44:25 -0800596 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800597}
598
599
U-Stream\Leeae25a442012-02-17 17:48:16 -0800600void XMLNode::DeleteChild( XMLNode* node )
601{
602 TIXMLASSERT( node->parent == this );
603 DELETE_NODE( node );
604}
605
606
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800607XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
608{
609 if ( lastChild ) {
610 TIXMLASSERT( firstChild );
611 TIXMLASSERT( lastChild->next == 0 );
612 lastChild->next = addThis;
613 addThis->prev = lastChild;
614 lastChild = addThis;
615
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800616 addThis->next = 0;
617 }
618 else {
619 TIXMLASSERT( firstChild == 0 );
620 firstChild = lastChild = addThis;
621
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622 addThis->prev = 0;
623 addThis->next = 0;
624 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800625 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800626 return addThis;
627}
628
629
Lee Thomason1ff38e02012-02-14 18:18:16 -0800630XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
631{
632 if ( firstChild ) {
633 TIXMLASSERT( lastChild );
634 TIXMLASSERT( firstChild->prev == 0 );
635
636 firstChild->prev = addThis;
637 addThis->next = firstChild;
638 firstChild = addThis;
639
Lee Thomason1ff38e02012-02-14 18:18:16 -0800640 addThis->prev = 0;
641 }
642 else {
643 TIXMLASSERT( lastChild == 0 );
644 firstChild = lastChild = addThis;
645
Lee Thomason1ff38e02012-02-14 18:18:16 -0800646 addThis->prev = 0;
647 addThis->next = 0;
648 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800649 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800650 return addThis;
651}
652
653
654XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
655{
656 TIXMLASSERT( afterThis->parent == this );
657 if ( afterThis->parent != this )
658 return 0;
659
660 if ( afterThis->next == 0 ) {
661 // The last node or the only node.
662 return InsertEndChild( addThis );
663 }
664 addThis->prev = afterThis;
665 addThis->next = afterThis->next;
666 afterThis->next->prev = addThis;
667 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800668 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800669 return addThis;
670}
671
672
673
674
Lee Thomason56bdd022012-02-09 18:16:58 -0800675const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800676{
677 for( XMLNode* node=firstChild; node; node=node->next ) {
678 XMLElement* element = node->ToElement();
679 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800680 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800681 return element;
682 }
683 }
684 }
685 return 0;
686}
687
688
Lee Thomason56bdd022012-02-09 18:16:58 -0800689const XMLElement* XMLNode::LastChildElement( const char* value ) const
690{
691 for( XMLNode* node=lastChild; node; node=node->prev ) {
692 XMLElement* element = node->ToElement();
693 if ( element ) {
694 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
695 return element;
696 }
697 }
698 }
699 return 0;
700}
701
702
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800703const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
704{
705 for( XMLNode* element=this->next; element; element = element->next ) {
706 if ( element->ToElement()
707 && (!value || XMLUtil::StringEqual( value, element->Value() )))
708 {
709 return element->ToElement();
710 }
711 }
712 return 0;
713}
714
715
716const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
717{
718 for( XMLNode* element=this->prev; element; element = element->prev ) {
719 if ( element->ToElement()
720 && (!value || XMLUtil::StringEqual( value, element->Value() )))
721 {
722 return element->ToElement();
723 }
724 }
725 return 0;
726}
727
728
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800729char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800730{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800731 // This is a recursive method, but thinking about it "at the current level"
732 // it is a pretty simple flat list:
733 // <foo/>
734 // <!-- comment -->
735 //
736 // With a special case:
737 // <foo>
738 // </foo>
739 // <!-- comment -->
740 //
741 // Where the closing element (/foo) *must* be the next thing after the opening
742 // element, and the names must match. BUT the tricky bit is that the closing
743 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800744 //
745 // 'endTag' is the end tag for this node, it is returned by a call to a child.
746 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800747
Lee Thomason67d61312012-01-24 16:01:51 -0800748 while( p && *p ) {
749 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800750
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800751 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800752 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800753 break;
754 }
755
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800756 StrPair endTag;
757 p = node->ParseDeep( p, &endTag );
758 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800759 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800760 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800761 if ( !document->Error() ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700762 document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800763 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800764 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800765 }
766
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800767 // We read the end tag. Return it to the parent.
768 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
769 if ( parentEnd ) {
PKEuSc28ba3a2012-07-16 03:08:47 -0700770 *parentEnd = static_cast<XMLElement*>(node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800771 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800772 DELETE_NODE( node );
773 return p;
774 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800775
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800776 // Handle an end tag returned to this level.
777 // And handle a bunch of annoying errors.
778 XMLElement* ele = node->ToElement();
779 if ( ele ) {
780 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700781 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800782 p = 0;
783 }
784 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700785 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800786 p = 0;
787 }
788 else if ( !endTag.Empty() ) {
789 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700790 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800791 p = 0;
792 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800793 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800794 }
795 if ( p == 0 ) {
796 DELETE_NODE( node );
797 node = 0;
798 }
799 if ( node ) {
800 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800801 }
802 }
803 return 0;
804}
805
Lee Thomason5492a1c2012-01-23 15:32:10 -0800806// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800807char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800808{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800809 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800810 if ( this->CData() ) {
811 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800812 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700813 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800814 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800815 return p;
816 }
817 else {
Lee Thomason6f381b72012-03-02 12:59:39 -0800818 p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800819 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700820 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800821 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800822 if ( p && *p ) {
823 return p-1;
824 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800825 }
826 return 0;
827}
828
829
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800830XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
831{
832 if ( !doc ) {
833 doc = document;
834 }
835 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
836 text->SetCData( this->CData() );
837 return text;
838}
839
840
841bool XMLText::ShallowEqual( const XMLNode* compare ) const
842{
843 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
844}
845
846
Lee Thomason56bdd022012-02-09 18:16:58 -0800847bool XMLText::Accept( XMLVisitor* visitor ) const
848{
849 return visitor->Visit( *this );
850}
851
852
Lee Thomason3f57d272012-01-11 15:30:03 -0800853// --------- XMLComment ---------- //
854
Lee Thomasone4422302012-01-20 17:59:50 -0800855XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800856{
857}
858
859
Lee Thomasonce0763e2012-01-11 15:43:54 -0800860XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800861{
Lee Thomasond923c672012-01-23 08:44:25 -0800862 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800863}
864
865
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800866char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800867{
868 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800869 const char* start = p;
870 p = value.ParseText( p, "-->", StrPair::COMMENT );
871 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700872 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800873 }
874 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800875}
876
877
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800878XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
879{
880 if ( !doc ) {
881 doc = document;
882 }
883 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
884 return comment;
885}
886
887
888bool XMLComment::ShallowEqual( const XMLNode* compare ) const
889{
890 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
891}
892
893
Lee Thomason751da522012-02-10 08:50:51 -0800894bool XMLComment::Accept( XMLVisitor* visitor ) const
895{
896 return visitor->Visit( *this );
897}
Lee Thomason56bdd022012-02-09 18:16:58 -0800898
899
Lee Thomason50f97b22012-02-11 16:33:40 -0800900// --------- XMLDeclaration ---------- //
901
902XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
903{
904}
905
906
907XMLDeclaration::~XMLDeclaration()
908{
909 //printf( "~XMLDeclaration\n" );
910}
911
912
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800914{
915 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800916 const char* start = p;
917 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
918 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700919 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800920 }
921 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800922}
923
924
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800925XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
926{
927 if ( !doc ) {
928 doc = document;
929 }
930 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
931 return dec;
932}
933
934
935bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
936{
937 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
938}
939
940
941
Lee Thomason50f97b22012-02-11 16:33:40 -0800942bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
943{
944 return visitor->Visit( *this );
945}
946
947// --------- XMLUnknown ---------- //
948
949XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
950{
951}
952
953
954XMLUnknown::~XMLUnknown()
955{
956}
957
958
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800959char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800960{
961 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800962 const char* start = p;
963
964 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
965 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700966 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800967 }
968 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800969}
970
971
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
973{
974 if ( !doc ) {
975 doc = document;
976 }
977 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
978 return text;
979}
980
981
982bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
983{
984 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
985}
986
987
Lee Thomason50f97b22012-02-11 16:33:40 -0800988bool XMLUnknown::Accept( XMLVisitor* visitor ) const
989{
990 return visitor->Visit( *this );
991}
992
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800993// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -0800994char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800995{
Lee Thomason78a773d2012-07-02 10:10:19 -0700996 // Parse using the name rules: bug fix, was using ParseText before
997 p = name.ParseName( p );
Lee Thomason22aead12012-01-23 13:29:35 -0800998 if ( !p || !*p ) return 0;
999
Lee Thomason78a773d2012-07-02 10:10:19 -07001000 // Skip white space before =
1001 p = XMLUtil::SkipWhiteSpace( p );
1002 if ( !p || *p != '=' ) return 0;
1003
1004 ++p; // move up to opening quote
1005 p = XMLUtil::SkipWhiteSpace( p );
1006 if ( *p != '\"' && *p != '\'' ) return 0;
1007
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001008 char endTag[2] = { *p, 0 };
Lee Thomason78a773d2012-07-02 10:10:19 -07001009 ++p; // move past opening quote
1010
Lee Thomason6f381b72012-03-02 12:59:39 -08001011 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001012 return p;
1013}
1014
1015
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001016void XMLAttribute::SetName( const char* n )
1017{
1018 name.SetStr( n );
1019}
1020
1021
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001022int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001023{
Lee Thomason21be8822012-07-15 17:27:22 -07001024 if ( XMLUtil::ToInt( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001025 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001026 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001027}
1028
1029
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001030int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001031{
Lee Thomason21be8822012-07-15 17:27:22 -07001032 if ( XMLUtil::ToUnsigned( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001033 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001034 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001035}
1036
1037
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001038int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001039{
Lee Thomason21be8822012-07-15 17:27:22 -07001040 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001041 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001042 }
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001043 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001044}
1045
1046
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001047int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001048{
Lee Thomason21be8822012-07-15 17:27:22 -07001049 if ( XMLUtil::ToFloat( Value(), value ))
1050 return XML_NO_ERROR;
1051 return XML_WRONG_ATTRIBUTE_TYPE;
1052}
1053
1054
1055int XMLAttribute::QueryDoubleValue( double* value ) const
1056{
1057 if ( XMLUtil::ToDouble( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001058 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001059 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001060}
1061
1062
1063void XMLAttribute::SetAttribute( const char* v )
1064{
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001065 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001066}
1067
1068
Lee Thomason1ff38e02012-02-14 18:18:16 -08001069void XMLAttribute::SetAttribute( int v )
1070{
1071 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001072 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001073 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001074}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001075
1076
1077void XMLAttribute::SetAttribute( unsigned v )
1078{
1079 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001080 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001081 value.SetStr( buf );
1082}
1083
1084
1085void XMLAttribute::SetAttribute( bool v )
1086{
1087 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001088 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001089 value.SetStr( buf );
1090}
1091
1092void XMLAttribute::SetAttribute( double v )
1093{
1094 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001095 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001096 value.SetStr( buf );
1097}
1098
1099void XMLAttribute::SetAttribute( float v )
1100{
1101 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001102 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001103 value.SetStr( buf );
1104}
1105
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001106
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001107// --------- XMLElement ---------- //
1108XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001109 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001110 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001111{
1112}
1113
1114
1115XMLElement::~XMLElement()
1116{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001117 while( rootAttribute ) {
1118 XMLAttribute* next = rootAttribute->next;
1119 DELETE_ATTRIBUTE( rootAttribute );
1120 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001121 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001122}
1123
1124
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001125XMLAttribute* XMLElement::FindAttribute( const char* name )
1126{
1127 XMLAttribute* a = 0;
1128 for( a=rootAttribute; a; a = a->next ) {
1129 if ( XMLUtil::StringEqual( a->Name(), name ) )
1130 return a;
1131 }
1132 return 0;
1133}
1134
1135
1136const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1137{
1138 XMLAttribute* a = 0;
1139 for( a=rootAttribute; a; a = a->next ) {
1140 if ( XMLUtil::StringEqual( a->Name(), name ) )
1141 return a;
1142 }
1143 return 0;
1144}
1145
1146
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001147const char* XMLElement::Attribute( const char* name, const char* value ) const
1148{
1149 const XMLAttribute* a = FindAttribute( name );
1150 if ( !a )
1151 return 0;
1152 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1153 return a->Value();
1154 return 0;
1155}
1156
1157
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001158const char* XMLElement::GetText() const
1159{
1160 if ( FirstChild() && FirstChild()->ToText() ) {
1161 return FirstChild()->ToText()->Value();
1162 }
1163 return 0;
1164}
1165
1166
Lee Thomason21be8822012-07-15 17:27:22 -07001167int XMLElement::QueryIntText( int* _value ) const
1168{
1169 if ( FirstChild() && FirstChild()->ToText() ) {
1170 const char* t = FirstChild()->ToText()->Value();
1171 if ( XMLUtil::ToInt( t, _value ) ) {
1172 return XML_SUCCESS;
1173 }
1174 return XML_CAN_NOT_CONVERT_TEXT;
1175 }
1176 return XML_NO_TEXT_NODE;
1177}
1178
1179
1180int XMLElement::QueryUnsignedText( unsigned* _value ) const
1181{
1182 if ( FirstChild() && FirstChild()->ToText() ) {
1183 const char* t = FirstChild()->ToText()->Value();
1184 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1185 return XML_SUCCESS;
1186 }
1187 return XML_CAN_NOT_CONVERT_TEXT;
1188 }
1189 return XML_NO_TEXT_NODE;
1190}
1191
1192
1193int XMLElement::QueryBoolText( bool* _value ) const
1194{
1195 if ( FirstChild() && FirstChild()->ToText() ) {
1196 const char* t = FirstChild()->ToText()->Value();
1197 if ( XMLUtil::ToBool( t, _value ) ) {
1198 return XML_SUCCESS;
1199 }
1200 return XML_CAN_NOT_CONVERT_TEXT;
1201 }
1202 return XML_NO_TEXT_NODE;
1203}
1204
1205
1206int XMLElement::QueryDoubleText( double* _value ) const
1207{
1208 if ( FirstChild() && FirstChild()->ToText() ) {
1209 const char* t = FirstChild()->ToText()->Value();
1210 if ( XMLUtil::ToDouble( t, _value ) ) {
1211 return XML_SUCCESS;
1212 }
1213 return XML_CAN_NOT_CONVERT_TEXT;
1214 }
1215 return XML_NO_TEXT_NODE;
1216}
1217
1218
1219int XMLElement::QueryFloatText( float* _value ) const
1220{
1221 if ( FirstChild() && FirstChild()->ToText() ) {
1222 const char* t = FirstChild()->ToText()->Value();
1223 if ( XMLUtil::ToFloat( t, _value ) ) {
1224 return XML_SUCCESS;
1225 }
1226 return XML_CAN_NOT_CONVERT_TEXT;
1227 }
1228 return XML_NO_TEXT_NODE;
1229}
1230
1231
1232
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001233XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1234{
Lee Thomason5e3803c2012-04-16 08:57:05 -07001235 XMLAttribute* last = 0;
1236 XMLAttribute* attrib = 0;
1237 for( attrib = rootAttribute;
1238 attrib;
1239 last = attrib, attrib = attrib->next )
1240 {
1241 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1242 break;
1243 }
1244 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001245 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001246 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001247 attrib->memPool = &document->attributePool;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001248 if ( last ) {
1249 last->next = attrib;
1250 }
1251 else {
1252 rootAttribute = attrib;
1253 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001254 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001255 }
1256 return attrib;
1257}
1258
1259
U-Stream\Leeae25a442012-02-17 17:48:16 -08001260void XMLElement::DeleteAttribute( const char* name )
1261{
1262 XMLAttribute* prev = 0;
1263 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1264 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1265 if ( prev ) {
1266 prev->next = a->next;
1267 }
1268 else {
1269 rootAttribute = a->next;
1270 }
1271 DELETE_ATTRIBUTE( a );
1272 break;
1273 }
1274 prev = a;
1275 }
1276}
1277
1278
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001279char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001280{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001281 const char* start = p;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001282 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001283
1284 // Read the attributes.
1285 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001286 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001287 if ( !p || !(*p) ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001288 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001289 return 0;
1290 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001291
1292 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001293 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001294 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001295 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001296
Lee Thomason6f381b72012-03-02 12:59:39 -08001297 p = attrib->ParseDeep( p, document->ProcessEntities() );
Lee Thomasond6277762012-02-22 16:00:12 -08001298 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001299 DELETE_ATTRIBUTE( attrib );
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001300 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001301 return 0;
1302 }
Lee Thomason5e3803c2012-04-16 08:57:05 -07001303 // There is a minor bug here: if the attribute in the source xml
1304 // document is duplicated, it will not be detected and the
1305 // attribute will be doubly added. However, tracking the 'prevAttribute'
1306 // avoids re-scanning the attribute list. Preferring performance for
1307 // now, may reconsider in the future.
1308 if ( prevAttribute ) {
1309 prevAttribute->next = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001310 }
1311 else {
1312 rootAttribute = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001313 }
Lee Thomason97088852012-04-18 11:39:42 -07001314 prevAttribute = attrib;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001315 }
Lee Thomasone4422302012-01-20 17:59:50 -08001316 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001317 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001318 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001319 return p+2; // done; sealed element.
1320 }
Lee Thomasone4422302012-01-20 17:59:50 -08001321 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001322 else if ( *p == '>' ) {
1323 ++p;
1324 break;
1325 }
Lee Thomasone4422302012-01-20 17:59:50 -08001326 else {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001327 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001328 return 0;
1329 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001330 }
Lee Thomason67d61312012-01-24 16:01:51 -08001331 return p;
1332}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001333
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334
Lee Thomason67d61312012-01-24 16:01:51 -08001335//
1336// <ele></ele>
1337// <ele>foo<b>bar</b></ele>
1338//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001339char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001340{
1341 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001342 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001343 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001344
1345 // The closing element is the </element> form. It is
1346 // parsed just like a regular element then deleted from
1347 // the DOM.
1348 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001349 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001350 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351 }
Lee Thomason67d61312012-01-24 16:01:51 -08001352
Lee Thomason56bdd022012-02-09 18:16:58 -08001353 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001354 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001355
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001356 p = ParseAttributes( p );
1357 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001358 return p;
1359
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001360 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001361 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001362}
1363
1364
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001365
1366XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1367{
1368 if ( !doc ) {
1369 doc = document;
1370 }
1371 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1372 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1373 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1374 }
1375 return element;
1376}
1377
1378
1379bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1380{
1381 const XMLElement* other = compare->ToElement();
1382 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1383
1384 const XMLAttribute* a=FirstAttribute();
1385 const XMLAttribute* b=other->FirstAttribute();
1386
1387 while ( a && b ) {
1388 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1389 return false;
1390 }
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001391 a = a->Next();
1392 b = b->Next();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001393 }
1394 if ( a || b ) {
1395 // different count
1396 return false;
1397 }
1398 return true;
1399 }
1400 return false;
1401}
1402
1403
Lee Thomason751da522012-02-10 08:50:51 -08001404bool XMLElement::Accept( XMLVisitor* visitor ) const
1405{
1406 if ( visitor->VisitEnter( *this, rootAttribute ) )
1407 {
1408 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1409 {
1410 if ( !node->Accept( visitor ) )
1411 break;
1412 }
1413 }
1414 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001415}
Lee Thomason56bdd022012-02-09 18:16:58 -08001416
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001417
Lee Thomason3f57d272012-01-11 15:30:03 -08001418// --------- XMLDocument ----------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001419XMLDocument::XMLDocument( bool _processEntities ) :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001420 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001421 writeBOM( false ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001422 processEntities( _processEntities ),
1423 errorID( 0 ),
1424 errorStr1( 0 ),
1425 errorStr2( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001426 charBuffer( 0 )
1427{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001428 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001429}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001430
1431
Lee Thomason3f57d272012-01-11 15:30:03 -08001432XMLDocument::~XMLDocument()
1433{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001434 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001435 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001436
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001437#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001438 textPool.Trace( "text" );
1439 elementPool.Trace( "element" );
1440 commentPool.Trace( "comment" );
1441 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001442#endif
1443
Lee Thomason455c9d42012-02-06 09:14:14 -08001444 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1445 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1446 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1447 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001448}
1449
1450
Lee Thomason18d68bd2012-01-26 18:17:26 -08001451void XMLDocument::InitDocument()
1452{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001453 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001454 errorStr1 = 0;
1455 errorStr2 = 0;
1456
1457 delete [] charBuffer;
1458 charBuffer = 0;
1459
1460}
1461
Lee Thomason3f57d272012-01-11 15:30:03 -08001462
Lee Thomason2c85a712012-01-31 08:24:24 -08001463XMLElement* XMLDocument::NewElement( const char* name )
1464{
Lee Thomasond1983222012-02-06 08:41:24 -08001465 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1466 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001467 ele->SetName( name );
1468 return ele;
1469}
1470
1471
Lee Thomason1ff38e02012-02-14 18:18:16 -08001472XMLComment* XMLDocument::NewComment( const char* str )
1473{
1474 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1475 comment->memPool = &commentPool;
1476 comment->SetValue( str );
1477 return comment;
1478}
1479
1480
1481XMLText* XMLDocument::NewText( const char* str )
1482{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001483 XMLText* text = new (textPool.Alloc()) XMLText( this );
1484 text->memPool = &textPool;
1485 text->SetValue( str );
1486 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001487}
1488
1489
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001490XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1491{
1492 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1493 dec->memPool = &commentPool;
Lee Thomasonf68c4382012-04-28 14:37:11 -07001494 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001495 return dec;
1496}
1497
1498
1499XMLUnknown* XMLDocument::NewUnknown( const char* str )
1500{
1501 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1502 unk->memPool = &commentPool;
1503 unk->SetValue( str );
1504 return unk;
1505}
1506
1507
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001508int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001509{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001510 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001511 InitDocument();
Martell186476c2012-09-06 16:41:46 +01001512 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001513
Martell186476c2012-09-06 16:41:46 +01001514 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1515 errno_t err = fopen_s(&fp, filename, "rb" );
1516 if ( !fp || err) {
1517 #else
1518 fp = fopen( filename, "rb" );
1519 if ( !fp) {
1520 #endif
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001521 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001522 return errorID;
1523 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001524 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001525 fclose( fp );
1526 return errorID;
1527}
1528
1529
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001530int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001531{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001532 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001533 InitDocument();
1534
1535 fseek( fp, 0, SEEK_END );
1536 unsigned size = ftell( fp );
1537 fseek( fp, 0, SEEK_SET );
1538
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001539 if ( size == 0 ) {
1540 return errorID;
1541 }
1542
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001543 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001544 size_t read = fread( charBuffer, 1, size, fp );
1545 if ( read != size ) {
1546 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1547 return errorID;
1548 }
1549
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001550 charBuffer[size] = 0;
1551
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001552 const char* p = charBuffer;
1553 p = XMLUtil::SkipWhiteSpace( p );
1554 p = XMLUtil::ReadBOM( p, &writeBOM );
1555 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001556 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001557 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001558 }
1559
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001560 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001561 return errorID;
1562}
1563
1564
Ken Miller81da1fb2012-04-09 23:32:26 -05001565int XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001566{
Martell186476c2012-09-06 16:41:46 +01001567 FILE* fp = 0;
1568 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1569 errno_t err = fopen_s(&fp, filename, "w" );
1570 if ( !fp || err) {
1571 #else
1572 fp = fopen( filename, "rb" );
1573 if ( !fp) {
1574 #endif
Lee Thomason7f7b1622012-03-24 12:49:03 -07001575 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001576 return errorID;
Martell186476c2012-09-06 16:41:46 +01001577 }
Ken Miller81da1fb2012-04-09 23:32:26 -05001578 SaveFile(fp);
1579 fclose( fp );
1580 return errorID;
1581}
1582
1583
1584int XMLDocument::SaveFile( FILE* fp )
1585{
1586 XMLPrinter stream( fp );
1587 Print( &stream );
1588 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001589}
1590
Lee Thomason1ff38e02012-02-14 18:18:16 -08001591
Lee Thomason7c913cd2012-01-26 18:32:34 -08001592int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001593{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001594 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001595 InitDocument();
1596
1597 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001598 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001599 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001600 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001601 p = XMLUtil::SkipWhiteSpace( p );
1602 p = XMLUtil::ReadBOM( p, &writeBOM );
1603 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001604 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001605 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001606 }
1607
Lee Thomason18d68bd2012-01-26 18:17:26 -08001608 size_t len = strlen( p );
1609 charBuffer = new char[ len+1 ];
1610 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001611
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001612
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001613 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001614 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001615}
1616
1617
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001618void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001619{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001620 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001621 if ( !streamer )
1622 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001623 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001624}
1625
1626
Lee Thomason67d61312012-01-24 16:01:51 -08001627void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1628{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001629 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001630 errorStr1 = str1;
1631 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001632}
1633
Lee Thomason5cae8972012-01-24 18:03:07 -08001634
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001635void XMLDocument::PrintError() const
1636{
1637 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001638 static const int LEN = 20;
1639 char buf1[LEN] = { 0 };
1640 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001641
1642 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001643 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001644 }
1645 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001646 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001647 }
1648
1649 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1650 errorID, buf1, buf2 );
1651 }
1652}
1653
1654
sniperbat25900882012-05-28 17:22:07 +08001655XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001656 elementJustOpened( false ),
1657 firstElement( true ),
1658 fp( file ),
1659 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001660 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001661 processEntities( true ),
1662 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001663{
Lee Thomason857b8682012-01-25 17:50:25 -08001664 for( int i=0; i<ENTITY_RANGE; ++i ) {
1665 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001666 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001667 }
1668 for( int i=0; i<NUM_ENTITIES; ++i ) {
1669 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1670 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001671 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001672 }
1673 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001674 restrictedEntityFlag[(int)'&'] = true;
1675 restrictedEntityFlag[(int)'<'] = true;
1676 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001677 buffer.Push( 0 );
1678}
1679
1680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001681void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001682{
1683 va_list va;
1684 va_start( va, format );
1685
1686 if ( fp ) {
1687 vfprintf( fp, format, va );
1688 }
1689 else {
1690 // This seems brutally complex. Haven't figured out a better
1691 // way on windows.
1692 #ifdef _MSC_VER
1693 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001694 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001695 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001696 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001697 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001698 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001699 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001700 }
1701 }
1702 char* p = buffer.PushArr( len ) - 1;
1703 memcpy( p, accumulator.Mem(), len+1 );
1704 #else
1705 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001706 // Close out and re-start the va-args
1707 va_end( va );
1708 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001709 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001710 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001711 #endif
1712 }
1713 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001714}
1715
1716
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001717void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001718{
1719 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001720 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001721 }
1722}
1723
1724
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001725void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001726{
Lee Thomason951d8832012-01-26 08:47:06 -08001727 // Look for runs of bytes between entities to print.
1728 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001729 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001730
Lee Thomason6f381b72012-03-02 12:59:39 -08001731 if ( processEntities ) {
1732 while ( *q ) {
1733 // Remember, char is sometimes signed. (How many times has that bitten me?)
1734 if ( *q > 0 && *q < ENTITY_RANGE ) {
1735 // Check for entities. If one is found, flush
1736 // the stream up until the entity, write the
1737 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001738 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001739 while ( p < q ) {
1740 Print( "%c", *p );
1741 ++p;
1742 }
1743 for( int i=0; i<NUM_ENTITIES; ++i ) {
1744 if ( entities[i].value == *q ) {
1745 Print( "&%s;", entities[i].pattern );
1746 break;
1747 }
1748 }
Lee Thomason951d8832012-01-26 08:47:06 -08001749 ++p;
1750 }
Lee Thomason951d8832012-01-26 08:47:06 -08001751 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001752 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001753 }
Lee Thomason951d8832012-01-26 08:47:06 -08001754 }
1755 // Flush the remaining string. This will be the entire
1756 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001757 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001758 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001759 }
Lee Thomason857b8682012-01-25 17:50:25 -08001760}
1761
U-Stream\Leeae25a442012-02-17 17:48:16 -08001762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001763void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001764{
1765 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1766 if ( writeBOM ) {
1767 Print( "%s", bom );
1768 }
1769 if ( writeDec ) {
1770 PushDeclaration( "xml version=\"1.0\"" );
1771 }
1772}
1773
1774
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001775void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001776{
1777 if ( elementJustOpened ) {
1778 SealElement();
1779 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001780 stack.Push( name );
1781
sniperbat25900882012-05-28 17:22:07 +08001782 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001783 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001784 PrintSpace( depth );
1785 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001786
U-Stream\Leeae25a442012-02-17 17:48:16 -08001787 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001788 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001789 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001790 ++depth;
1791}
1792
1793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001794void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001795{
1796 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001797 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001799 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001800}
1801
1802
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001803void XMLPrinter::PushAttribute( const char* name, int v )
1804{
1805 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001806 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001807 PushAttribute( name, buf );
1808}
1809
1810
1811void XMLPrinter::PushAttribute( const char* name, unsigned v )
1812{
1813 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001814 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001815 PushAttribute( name, buf );
1816}
1817
1818
1819void XMLPrinter::PushAttribute( const char* name, bool v )
1820{
1821 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001822 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001823 PushAttribute( name, buf );
1824}
1825
1826
1827void XMLPrinter::PushAttribute( const char* name, double v )
1828{
1829 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001830 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001831 PushAttribute( name, buf );
1832}
1833
1834
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001835void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001836{
1837 --depth;
1838 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001839
1840 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001841 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001842 }
1843 else {
sniperbat25900882012-05-28 17:22:07 +08001844 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001845 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001846 PrintSpace( depth );
1847 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001848 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001849 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001850
1851 if ( textDepth == depth )
1852 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001853 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001854 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001855 elementJustOpened = false;
1856}
1857
1858
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001859void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001860{
1861 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001862 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001863}
1864
1865
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001866void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001867{
Lee Thomason56bdd022012-02-09 18:16:58 -08001868 textDepth = depth-1;
1869
Lee Thomason5cae8972012-01-24 18:03:07 -08001870 if ( elementJustOpened ) {
1871 SealElement();
1872 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001873 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001874 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001875 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001876 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001877 }
1878 else {
1879 PrintString( text, true );
1880 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001881}
1882
Lee Thomason21be8822012-07-15 17:27:22 -07001883void XMLPrinter::PushText( int value )
1884{
1885 char buf[BUF_SIZE];
1886 XMLUtil::ToStr( value, buf, BUF_SIZE );
1887 PushText( buf, false );
1888}
1889
1890
1891void XMLPrinter::PushText( unsigned value )
1892{
1893 char buf[BUF_SIZE];
1894 XMLUtil::ToStr( value, buf, BUF_SIZE );
1895 PushText( buf, false );
1896}
1897
1898
1899void XMLPrinter::PushText( bool value )
1900{
1901 char buf[BUF_SIZE];
1902 XMLUtil::ToStr( value, buf, BUF_SIZE );
1903 PushText( buf, false );
1904}
1905
1906
1907void XMLPrinter::PushText( float value )
1908{
1909 char buf[BUF_SIZE];
1910 XMLUtil::ToStr( value, buf, BUF_SIZE );
1911 PushText( buf, false );
1912}
1913
1914
1915void XMLPrinter::PushText( double value )
1916{
1917 char buf[BUF_SIZE];
1918 XMLUtil::ToStr( value, buf, BUF_SIZE );
1919 PushText( buf, false );
1920}
1921
Lee Thomason5cae8972012-01-24 18:03:07 -08001922
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001923void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001924{
1925 if ( elementJustOpened ) {
1926 SealElement();
1927 }
sniperbat25900882012-05-28 17:22:07 +08001928 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001929 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001930 PrintSpace( depth );
1931 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001932 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001933 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001934}
Lee Thomason751da522012-02-10 08:50:51 -08001935
1936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001938{
1939 if ( elementJustOpened ) {
1940 SealElement();
1941 }
sniperbat25900882012-05-28 17:22:07 +08001942 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001943 Print( "\n" );
1944 PrintSpace( depth );
1945 }
1946 firstElement = false;
1947 Print( "<?%s?>", value );
1948}
1949
1950
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001951void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001952{
1953 if ( elementJustOpened ) {
1954 SealElement();
1955 }
sniperbat25900882012-05-28 17:22:07 +08001956 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001957 Print( "\n" );
1958 PrintSpace( depth );
1959 }
1960 firstElement = false;
1961 Print( "<!%s>", value );
1962}
1963
1964
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001965bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001966{
Lee Thomason6f381b72012-03-02 12:59:39 -08001967 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001968 if ( doc.HasBOM() ) {
1969 PushHeader( true, false );
1970 }
1971 return true;
1972}
1973
1974
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001975bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001976{
1977 OpenElement( element.Name() );
1978 while ( attribute ) {
1979 PushAttribute( attribute->Name(), attribute->Value() );
1980 attribute = attribute->Next();
1981 }
1982 return true;
1983}
1984
1985
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001986bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08001987{
1988 CloseElement();
1989 return true;
1990}
1991
1992
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001993bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001994{
Lee Thomasond6277762012-02-22 16:00:12 -08001995 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001996 return true;
1997}
1998
1999
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002000bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002001{
2002 PushComment( comment.Value() );
2003 return true;
2004}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002005
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002006bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002007{
2008 PushDeclaration( declaration.Value() );
2009 return true;
2010}
2011
2012
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002013bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002014{
2015 PushUnknown( unknown.Value() );
2016 return true;
2017}