blob: 8069d04049f8919d2f0ef9324d4e4ff2ecdee73f [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();
1512
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001513#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001514#pragma warning ( push )
1515#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001516#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001517 FILE* fp = fopen( filename, "rb" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001518#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001519#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001520#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001521 if ( !fp ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001522 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001523 return errorID;
1524 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001525 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001526 fclose( fp );
1527 return errorID;
1528}
1529
1530
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001531int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001532{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001533 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001534 InitDocument();
1535
1536 fseek( fp, 0, SEEK_END );
1537 unsigned size = ftell( fp );
1538 fseek( fp, 0, SEEK_SET );
1539
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001540 if ( size == 0 ) {
1541 return errorID;
1542 }
1543
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001544 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001545 size_t read = fread( charBuffer, 1, size, fp );
1546 if ( read != size ) {
1547 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1548 return errorID;
1549 }
1550
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001551 charBuffer[size] = 0;
1552
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001553 const char* p = charBuffer;
1554 p = XMLUtil::SkipWhiteSpace( p );
1555 p = XMLUtil::ReadBOM( p, &writeBOM );
1556 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001557 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001558 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001559 }
1560
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001561 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001562 return errorID;
1563}
1564
1565
Ken Miller81da1fb2012-04-09 23:32:26 -05001566int XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001567{
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001568#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001569#pragma warning ( push )
1570#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001572 FILE* fp = fopen( filename, "w" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001573#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001574#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001575#endif
Ken Miller81da1fb2012-04-09 23:32:26 -05001576 if ( !fp ) {
Lee Thomason7f7b1622012-03-24 12:49:03 -07001577 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001578 return errorID;
Lee Thomason7f7b1622012-03-24 12:49:03 -07001579 }
Ken Miller81da1fb2012-04-09 23:32:26 -05001580 SaveFile(fp);
1581 fclose( fp );
1582 return errorID;
1583}
1584
1585
1586int XMLDocument::SaveFile( FILE* fp )
1587{
1588 XMLPrinter stream( fp );
1589 Print( &stream );
1590 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001591}
1592
Lee Thomason1ff38e02012-02-14 18:18:16 -08001593
Lee Thomason7c913cd2012-01-26 18:32:34 -08001594int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001595{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001596 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001597 InitDocument();
1598
1599 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001600 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001601 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001602 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001603 p = XMLUtil::SkipWhiteSpace( p );
1604 p = XMLUtil::ReadBOM( p, &writeBOM );
1605 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001606 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001607 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001608 }
1609
Lee Thomason18d68bd2012-01-26 18:17:26 -08001610 size_t len = strlen( p );
1611 charBuffer = new char[ len+1 ];
1612 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001613
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001614
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001615 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001616 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001617}
1618
1619
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001620void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001621{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001622 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001623 if ( !streamer )
1624 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001625 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001626}
1627
1628
Lee Thomason67d61312012-01-24 16:01:51 -08001629void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1630{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001631 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001632 errorStr1 = str1;
1633 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001634}
1635
Lee Thomason5cae8972012-01-24 18:03:07 -08001636
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001637void XMLDocument::PrintError() const
1638{
1639 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001640 static const int LEN = 20;
1641 char buf1[LEN] = { 0 };
1642 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001643
1644 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001645 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001646 }
1647 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001648 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001649 }
1650
1651 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1652 errorID, buf1, buf2 );
1653 }
1654}
1655
1656
sniperbat25900882012-05-28 17:22:07 +08001657XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001658 elementJustOpened( false ),
1659 firstElement( true ),
1660 fp( file ),
1661 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001662 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001663 processEntities( true ),
1664 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001665{
Lee Thomason857b8682012-01-25 17:50:25 -08001666 for( int i=0; i<ENTITY_RANGE; ++i ) {
1667 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001668 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001669 }
1670 for( int i=0; i<NUM_ENTITIES; ++i ) {
1671 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1672 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001673 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001674 }
1675 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001676 restrictedEntityFlag[(int)'&'] = true;
1677 restrictedEntityFlag[(int)'<'] = true;
1678 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001679 buffer.Push( 0 );
1680}
1681
1682
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001683void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001684{
1685 va_list va;
1686 va_start( va, format );
1687
1688 if ( fp ) {
1689 vfprintf( fp, format, va );
1690 }
1691 else {
1692 // This seems brutally complex. Haven't figured out a better
1693 // way on windows.
1694 #ifdef _MSC_VER
1695 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001696 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001697 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001698 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001699 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001700 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001701 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001702 }
1703 }
1704 char* p = buffer.PushArr( len ) - 1;
1705 memcpy( p, accumulator.Mem(), len+1 );
1706 #else
1707 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001708 // Close out and re-start the va-args
1709 va_end( va );
1710 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001711 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001712 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001713 #endif
1714 }
1715 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001716}
1717
1718
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001719void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001720{
1721 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001722 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001723 }
1724}
1725
1726
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001727void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001728{
Lee Thomason951d8832012-01-26 08:47:06 -08001729 // Look for runs of bytes between entities to print.
1730 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001732
Lee Thomason6f381b72012-03-02 12:59:39 -08001733 if ( processEntities ) {
1734 while ( *q ) {
1735 // Remember, char is sometimes signed. (How many times has that bitten me?)
1736 if ( *q > 0 && *q < ENTITY_RANGE ) {
1737 // Check for entities. If one is found, flush
1738 // the stream up until the entity, write the
1739 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001740 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001741 while ( p < q ) {
1742 Print( "%c", *p );
1743 ++p;
1744 }
1745 for( int i=0; i<NUM_ENTITIES; ++i ) {
1746 if ( entities[i].value == *q ) {
1747 Print( "&%s;", entities[i].pattern );
1748 break;
1749 }
1750 }
Lee Thomason951d8832012-01-26 08:47:06 -08001751 ++p;
1752 }
Lee Thomason951d8832012-01-26 08:47:06 -08001753 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001754 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001755 }
Lee Thomason951d8832012-01-26 08:47:06 -08001756 }
1757 // Flush the remaining string. This will be the entire
1758 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001759 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001760 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001761 }
Lee Thomason857b8682012-01-25 17:50:25 -08001762}
1763
U-Stream\Leeae25a442012-02-17 17:48:16 -08001764
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001765void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001766{
1767 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1768 if ( writeBOM ) {
1769 Print( "%s", bom );
1770 }
1771 if ( writeDec ) {
1772 PushDeclaration( "xml version=\"1.0\"" );
1773 }
1774}
1775
1776
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001777void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001778{
1779 if ( elementJustOpened ) {
1780 SealElement();
1781 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001782 stack.Push( name );
1783
sniperbat25900882012-05-28 17:22:07 +08001784 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001785 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001786 PrintSpace( depth );
1787 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001788
U-Stream\Leeae25a442012-02-17 17:48:16 -08001789 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001790 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001791 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001792 ++depth;
1793}
1794
1795
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001796void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001797{
1798 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001799 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001801 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001802}
1803
1804
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001805void XMLPrinter::PushAttribute( const char* name, int v )
1806{
1807 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001808 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001809 PushAttribute( name, buf );
1810}
1811
1812
1813void XMLPrinter::PushAttribute( const char* name, unsigned v )
1814{
1815 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001816 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001817 PushAttribute( name, buf );
1818}
1819
1820
1821void XMLPrinter::PushAttribute( const char* name, bool v )
1822{
1823 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001824 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001825 PushAttribute( name, buf );
1826}
1827
1828
1829void XMLPrinter::PushAttribute( const char* name, double v )
1830{
1831 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001832 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001833 PushAttribute( name, buf );
1834}
1835
1836
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001837void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001838{
1839 --depth;
1840 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001841
1842 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001843 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001844 }
1845 else {
sniperbat25900882012-05-28 17:22:07 +08001846 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001847 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001848 PrintSpace( depth );
1849 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001850 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001851 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001852
1853 if ( textDepth == depth )
1854 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001855 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001856 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001857 elementJustOpened = false;
1858}
1859
1860
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001861void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001862{
1863 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001864 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001865}
1866
1867
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001868void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001869{
Lee Thomason56bdd022012-02-09 18:16:58 -08001870 textDepth = depth-1;
1871
Lee Thomason5cae8972012-01-24 18:03:07 -08001872 if ( elementJustOpened ) {
1873 SealElement();
1874 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001875 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001876 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001877 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001878 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001879 }
1880 else {
1881 PrintString( text, true );
1882 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001883}
1884
Lee Thomason21be8822012-07-15 17:27:22 -07001885void XMLPrinter::PushText( int value )
1886{
1887 char buf[BUF_SIZE];
1888 XMLUtil::ToStr( value, buf, BUF_SIZE );
1889 PushText( buf, false );
1890}
1891
1892
1893void XMLPrinter::PushText( unsigned value )
1894{
1895 char buf[BUF_SIZE];
1896 XMLUtil::ToStr( value, buf, BUF_SIZE );
1897 PushText( buf, false );
1898}
1899
1900
1901void XMLPrinter::PushText( bool value )
1902{
1903 char buf[BUF_SIZE];
1904 XMLUtil::ToStr( value, buf, BUF_SIZE );
1905 PushText( buf, false );
1906}
1907
1908
1909void XMLPrinter::PushText( float value )
1910{
1911 char buf[BUF_SIZE];
1912 XMLUtil::ToStr( value, buf, BUF_SIZE );
1913 PushText( buf, false );
1914}
1915
1916
1917void XMLPrinter::PushText( double value )
1918{
1919 char buf[BUF_SIZE];
1920 XMLUtil::ToStr( value, buf, BUF_SIZE );
1921 PushText( buf, false );
1922}
1923
Lee Thomason5cae8972012-01-24 18:03:07 -08001924
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001925void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001926{
1927 if ( elementJustOpened ) {
1928 SealElement();
1929 }
sniperbat25900882012-05-28 17:22:07 +08001930 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001931 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001932 PrintSpace( depth );
1933 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001934 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001935 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001936}
Lee Thomason751da522012-02-10 08:50:51 -08001937
1938
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001939void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001940{
1941 if ( elementJustOpened ) {
1942 SealElement();
1943 }
sniperbat25900882012-05-28 17:22:07 +08001944 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001945 Print( "\n" );
1946 PrintSpace( depth );
1947 }
1948 firstElement = false;
1949 Print( "<?%s?>", value );
1950}
1951
1952
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001953void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001954{
1955 if ( elementJustOpened ) {
1956 SealElement();
1957 }
sniperbat25900882012-05-28 17:22:07 +08001958 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001959 Print( "\n" );
1960 PrintSpace( depth );
1961 }
1962 firstElement = false;
1963 Print( "<!%s>", value );
1964}
1965
1966
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001967bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001968{
Lee Thomason6f381b72012-03-02 12:59:39 -08001969 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001970 if ( doc.HasBOM() ) {
1971 PushHeader( true, false );
1972 }
1973 return true;
1974}
1975
1976
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001977bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001978{
1979 OpenElement( element.Name() );
1980 while ( attribute ) {
1981 PushAttribute( attribute->Name(), attribute->Value() );
1982 attribute = attribute->Next();
1983 }
1984 return true;
1985}
1986
1987
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001988bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08001989{
1990 CloseElement();
1991 return true;
1992}
1993
1994
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001995bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001996{
Lee Thomasond6277762012-02-22 16:00:12 -08001997 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001998 return true;
1999}
2000
2001
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002002bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002003{
2004 PushComment( comment.Value() );
2005 return true;
2006}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002007
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002008bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002009{
2010 PushDeclaration( declaration.Value() );
2011 return true;
2012}
2013
2014
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002015bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002016{
2017 PushUnknown( unknown.Value() );
2018 return true;
2019}