blob: 87063d3201f7909546fc4d4b534e718d266622d2 [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
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137 while( *p && (
138 XMLUtil::IsAlphaNum( (unsigned char) *p )
139 || *p == '_'
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -0700140 || *p == ':'
141 || (*p == '-' && p>start ) // can be in a name, but not lead it.
142 || (*p == '.' && p>start ) )) // can be in a name, but not lead it.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143 {
144 ++p;
145 }
146
147 if ( p > start ) {
148 Set( start, p, 0 );
149 return p;
150 }
151 return 0;
152}
153
154
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800155
Lee Thomasone4422302012-01-20 17:59:50 -0800156const char* StrPair::GetStr()
157{
158 if ( flags & NEEDS_FLUSH ) {
159 *end = 0;
Lee Thomason8ee79892012-01-25 17:44:30 -0800160 flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800161
Lee Thomason8ee79892012-01-25 17:44:30 -0800162 if ( flags ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800163 char* p = start; // the read pointer
164 char* q = start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800165
166 while( p < end ) {
Lee Thomason8ee79892012-01-25 17:44:30 -0800167 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800168 // CR-LF pair becomes LF
169 // CR alone becomes LF
170 // LF-CR becomes LF
171 if ( *(p+1) == LF ) {
172 p += 2;
173 }
174 else {
175 ++p;
176 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800177 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800178 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800179 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasone4422302012-01-20 17:59:50 -0800180 if ( *(p+1) == CR ) {
181 p += 2;
182 }
183 else {
184 ++p;
185 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800186 *q++ = LF;
Lee Thomasone4422302012-01-20 17:59:50 -0800187 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800188 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800189 // Entities handled by tinyXML2:
190 // - special entities in the entity table [in/out]
191 // - numeric character reference [in]
192 // &#20013; or &#x4e2d;
193
194 if ( *(p+1) == '#' ) {
195 char buf[10] = { 0 };
196 int len;
197 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
198 for( int i=0; i<len; ++i ) {
199 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800200 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800201 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800202 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800203 else {
PKEuSc28ba3a2012-07-16 03:08:47 -0700204 int i=0;
205 for(; i<NUM_ENTITIES; ++i ) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800206 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
207 && *(p+entities[i].length+1) == ';' )
208 {
209 // Found an entity convert;
210 *q = entities[i].value;
211 ++q;
212 p += entities[i].length + 2;
213 break;
214 }
215 }
216 if ( i == NUM_ENTITIES ) {
217 // fixme: treat as error?
218 ++p;
219 ++q;
220 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800221 }
222 }
Lee Thomasone4422302012-01-20 17:59:50 -0800223 else {
224 *q = *p;
225 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800226 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800227 }
228 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800229 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800232 }
233 return start;
234}
235
Lee Thomason2c85a712012-01-31 08:24:24 -0800236
Lee Thomasone4422302012-01-20 17:59:50 -0800237
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800238
Lee Thomason56bdd022012-02-09 18:16:58 -0800239// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800240
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800241const char* XMLUtil::ReadBOM( const char* p, bool* bom )
242{
243 *bom = false;
244 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
245 // Check for BOM:
246 if ( *(pu+0) == TIXML_UTF_LEAD_0
247 && *(pu+1) == TIXML_UTF_LEAD_1
248 && *(pu+2) == TIXML_UTF_LEAD_2 )
249 {
250 *bom = true;
251 p += 3;
252 }
253 return p;
254}
255
256
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800257void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
258{
259 const unsigned long BYTE_MASK = 0xBF;
260 const unsigned long BYTE_MARK = 0x80;
261 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
262
263 if (input < 0x80)
264 *length = 1;
265 else if ( input < 0x800 )
266 *length = 2;
267 else if ( input < 0x10000 )
268 *length = 3;
269 else if ( input < 0x200000 )
270 *length = 4;
271 else
272 { *length = 0; return; } // This code won't covert this correctly anyway.
273
274 output += *length;
275
276 // Scary scary fall throughs.
277 switch (*length)
278 {
279 case 4:
280 --output;
281 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
282 input >>= 6;
283 case 3:
284 --output;
285 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
286 input >>= 6;
287 case 2:
288 --output;
289 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
290 input >>= 6;
291 case 1:
292 --output;
293 *output = (char)(input | FIRST_BYTE_MARK[*length]);
294 }
295}
296
297
298const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
299{
300 // Presume an entity, and pull it out.
301 *length = 0;
302
303 if ( *(p+1) == '#' && *(p+2) )
304 {
305 unsigned long ucs = 0;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200306 ptrdiff_t delta = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800307 unsigned mult = 1;
308
309 if ( *(p+2) == 'x' )
310 {
311 // Hexadecimal.
312 if ( !*(p+3) ) return 0;
313
314 const char* q = p+3;
315 q = strchr( q, ';' );
316
317 if ( !q || !*q ) return 0;
318
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200319 delta = q-p;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800320 --q;
321
322 while ( *q != 'x' )
323 {
324 if ( *q >= '0' && *q <= '9' )
325 ucs += mult * (*q - '0');
326 else if ( *q >= 'a' && *q <= 'f' )
327 ucs += mult * (*q - 'a' + 10);
328 else if ( *q >= 'A' && *q <= 'F' )
329 ucs += mult * (*q - 'A' + 10 );
330 else
331 return 0;
332 mult *= 16;
333 --q;
334 }
335 }
336 else
337 {
338 // Decimal.
339 if ( !*(p+2) ) return 0;
340
341 const char* q = p+2;
342 q = strchr( q, ';' );
343
344 if ( !q || !*q ) return 0;
345
346 delta = q-p;
347 --q;
348
349 while ( *q != '#' )
350 {
351 if ( *q >= '0' && *q <= '9' )
352 ucs += mult * (*q - '0');
353 else
354 return 0;
355 mult *= 10;
356 --q;
357 }
358 }
359 // convert the UCS to UTF-8
360 ConvertUTF32ToUTF8( ucs, value, length );
361 return p + delta + 1;
362 }
363 return p+1;
364}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800365
366
Lee Thomason21be8822012-07-15 17:27:22 -0700367void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
368{
369 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
370}
371
372
373void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
374{
375 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
376}
377
378
379void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
380{
381 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
382}
383
384
385void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
386{
387 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
388}
389
390
391void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
392{
393 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
394}
395
396
397bool XMLUtil::ToInt( const char* str, int* value )
398{
399 if ( TIXML_SSCANF( str, "%d", value ) == 1 )
400 return true;
401 return false;
402}
403
404bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
405{
406 if ( TIXML_SSCANF( str, "%u", value ) == 1 )
407 return true;
408 return false;
409}
410
411bool XMLUtil::ToBool( const char* str, bool* value )
412{
413 int ival = 0;
414 if ( ToInt( str, &ival )) {
415 *value = (ival==0) ? false : true;
416 return true;
417 }
418 if ( StringEqual( str, "true" ) ) {
419 *value = true;
420 return true;
421 }
422 else if ( StringEqual( str, "false" ) ) {
423 *value = false;
424 return true;
425 }
426 return false;
427}
428
429
430bool XMLUtil::ToFloat( const char* str, float* value )
431{
432 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
433 return true;
434 }
435 return false;
436}
437
438bool XMLUtil::ToDouble( const char* str, double* value )
439{
440 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
441 return true;
442 }
443 return false;
444}
445
446
Lee Thomasond1983222012-02-06 08:41:24 -0800447char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800448{
449 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800450 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800451 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800452 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800453 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800454 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800455 }
456
457 // What is this thing?
458 // - Elements start with a letter or underscore, but xml is reserved.
459 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800460 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800461 // - Everthing else is unknown to tinyxml.
462 //
463
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800464 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800465 static const char* commentHeader = { "<!--" };
466 static const char* dtdHeader = { "<!" };
467 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800468 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800469
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800470 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800471 static const int commentHeaderLen = 4;
472 static const int dtdHeaderLen = 2;
473 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800474 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800475
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800476#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800477#pragma warning ( push )
478#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800479#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800480 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
481 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800482#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800483#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800484#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800485 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
486 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
487 returnNode->memPool = &commentPool;
488 p += xmlHeaderLen;
489 }
490 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800491 returnNode = new (commentPool.Alloc()) XMLComment( this );
492 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800493 p += commentHeaderLen;
494 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800495 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
496 XMLText* text = new (textPool.Alloc()) XMLText( this );
497 returnNode = text;
498 returnNode->memPool = &textPool;
499 p += cdataHeaderLen;
500 text->SetCData( true );
501 }
502 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
503 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
504 returnNode->memPool = &commentPool;
505 p += dtdHeaderLen;
506 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800507 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800508 returnNode = new (elementPool.Alloc()) XMLElement( this );
509 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800510 p += elementHeaderLen;
511 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800512 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800513 returnNode = new (textPool.Alloc()) XMLText( this );
514 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800515 p = start; // Back it up, all the text counts.
516 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
518 *node = returnNode;
519 return p;
520}
521
522
Lee Thomason751da522012-02-10 08:50:51 -0800523bool XMLDocument::Accept( XMLVisitor* visitor ) const
524{
525 if ( visitor->VisitEnter( *this ) )
526 {
527 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
528 {
529 if ( !node->Accept( visitor ) )
530 break;
531 }
532 }
533 return visitor->VisitExit( *this );
534}
Lee Thomason56bdd022012-02-09 18:16:58 -0800535
536
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800537// --------- XMLNode ----------- //
538
539XMLNode::XMLNode( XMLDocument* doc ) :
540 document( doc ),
541 parent( 0 ),
542 firstChild( 0 ), lastChild( 0 ),
543 prev( 0 ), next( 0 )
544{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800545}
546
547
548XMLNode::~XMLNode()
549{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800550 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800551 if ( parent ) {
552 parent->Unlink( this );
553 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800554}
555
556
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800557void XMLNode::SetValue( const char* str, bool staticMem )
558{
559 if ( staticMem )
560 value.SetInternedStr( str );
561 else
562 value.SetStr( str );
563}
564
565
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800566void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800567{
Lee Thomasond923c672012-01-23 08:44:25 -0800568 while( firstChild ) {
569 XMLNode* node = firstChild;
570 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800571
Lee Thomason43f59302012-02-06 18:18:11 -0800572 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800574 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800575}
576
577
578void XMLNode::Unlink( XMLNode* child )
579{
580 TIXMLASSERT( child->parent == this );
581 if ( child == firstChild )
582 firstChild = firstChild->next;
583 if ( child == lastChild )
584 lastChild = lastChild->prev;
585
586 if ( child->prev ) {
587 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588 }
Lee Thomasond923c672012-01-23 08:44:25 -0800589 if ( child->next ) {
590 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800591 }
Lee Thomasond923c672012-01-23 08:44:25 -0800592 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800593}
594
595
U-Stream\Leeae25a442012-02-17 17:48:16 -0800596void XMLNode::DeleteChild( XMLNode* node )
597{
598 TIXMLASSERT( node->parent == this );
599 DELETE_NODE( node );
600}
601
602
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800603XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
604{
605 if ( lastChild ) {
606 TIXMLASSERT( firstChild );
607 TIXMLASSERT( lastChild->next == 0 );
608 lastChild->next = addThis;
609 addThis->prev = lastChild;
610 lastChild = addThis;
611
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800612 addThis->next = 0;
613 }
614 else {
615 TIXMLASSERT( firstChild == 0 );
616 firstChild = lastChild = addThis;
617
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800618 addThis->prev = 0;
619 addThis->next = 0;
620 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800621 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800622 return addThis;
623}
624
625
Lee Thomason1ff38e02012-02-14 18:18:16 -0800626XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
627{
628 if ( firstChild ) {
629 TIXMLASSERT( lastChild );
630 TIXMLASSERT( firstChild->prev == 0 );
631
632 firstChild->prev = addThis;
633 addThis->next = firstChild;
634 firstChild = addThis;
635
Lee Thomason1ff38e02012-02-14 18:18:16 -0800636 addThis->prev = 0;
637 }
638 else {
639 TIXMLASSERT( lastChild == 0 );
640 firstChild = lastChild = addThis;
641
Lee Thomason1ff38e02012-02-14 18:18:16 -0800642 addThis->prev = 0;
643 addThis->next = 0;
644 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800645 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800646 return addThis;
647}
648
649
650XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
651{
652 TIXMLASSERT( afterThis->parent == this );
653 if ( afterThis->parent != this )
654 return 0;
655
656 if ( afterThis->next == 0 ) {
657 // The last node or the only node.
658 return InsertEndChild( addThis );
659 }
660 addThis->prev = afterThis;
661 addThis->next = afterThis->next;
662 afterThis->next->prev = addThis;
663 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800664 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800665 return addThis;
666}
667
668
669
670
Lee Thomason56bdd022012-02-09 18:16:58 -0800671const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800672{
673 for( XMLNode* node=firstChild; node; node=node->next ) {
674 XMLElement* element = node->ToElement();
675 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800676 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800677 return element;
678 }
679 }
680 }
681 return 0;
682}
683
684
Lee Thomason56bdd022012-02-09 18:16:58 -0800685const XMLElement* XMLNode::LastChildElement( const char* value ) const
686{
687 for( XMLNode* node=lastChild; node; node=node->prev ) {
688 XMLElement* element = node->ToElement();
689 if ( element ) {
690 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
691 return element;
692 }
693 }
694 }
695 return 0;
696}
697
698
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800699const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
700{
701 for( XMLNode* element=this->next; element; element = element->next ) {
702 if ( element->ToElement()
703 && (!value || XMLUtil::StringEqual( value, element->Value() )))
704 {
705 return element->ToElement();
706 }
707 }
708 return 0;
709}
710
711
712const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
713{
714 for( XMLNode* element=this->prev; element; element = element->prev ) {
715 if ( element->ToElement()
716 && (!value || XMLUtil::StringEqual( value, element->Value() )))
717 {
718 return element->ToElement();
719 }
720 }
721 return 0;
722}
723
724
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800725char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800726{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800727 // This is a recursive method, but thinking about it "at the current level"
728 // it is a pretty simple flat list:
729 // <foo/>
730 // <!-- comment -->
731 //
732 // With a special case:
733 // <foo>
734 // </foo>
735 // <!-- comment -->
736 //
737 // Where the closing element (/foo) *must* be the next thing after the opening
738 // element, and the names must match. BUT the tricky bit is that the closing
739 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800740 //
741 // 'endTag' is the end tag for this node, it is returned by a call to a child.
742 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800743
Lee Thomason67d61312012-01-24 16:01:51 -0800744 while( p && *p ) {
745 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800746
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800747 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800748 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800749 break;
750 }
751
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800752 StrPair endTag;
753 p = node->ParseDeep( p, &endTag );
754 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800755 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800756 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800757 if ( !document->Error() ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700758 document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800759 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800760 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800761 }
762
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800763 // We read the end tag. Return it to the parent.
764 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
765 if ( parentEnd ) {
PKEuSc28ba3a2012-07-16 03:08:47 -0700766 *parentEnd = static_cast<XMLElement*>(node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800767 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800768 DELETE_NODE( node );
769 return p;
770 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800771
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800772 // Handle an end tag returned to this level.
773 // And handle a bunch of annoying errors.
774 XMLElement* ele = node->ToElement();
775 if ( ele ) {
776 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700777 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800778 p = 0;
779 }
780 else 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() ) {
785 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700786 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800787 p = 0;
788 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800789 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800790 }
791 if ( p == 0 ) {
792 DELETE_NODE( node );
793 node = 0;
794 }
795 if ( node ) {
796 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800797 }
798 }
799 return 0;
800}
801
Lee Thomason5492a1c2012-01-23 15:32:10 -0800802// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800803char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800804{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800805 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800806 if ( this->CData() ) {
807 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800808 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700809 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800810 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800811 return p;
812 }
813 else {
Lee Thomason6f381b72012-03-02 12:59:39 -0800814 p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800815 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700816 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800817 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800818 if ( p && *p ) {
819 return p-1;
820 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800821 }
822 return 0;
823}
824
825
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800826XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
827{
828 if ( !doc ) {
829 doc = document;
830 }
831 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
832 text->SetCData( this->CData() );
833 return text;
834}
835
836
837bool XMLText::ShallowEqual( const XMLNode* compare ) const
838{
839 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
840}
841
842
Lee Thomason56bdd022012-02-09 18:16:58 -0800843bool XMLText::Accept( XMLVisitor* visitor ) const
844{
845 return visitor->Visit( *this );
846}
847
848
Lee Thomason3f57d272012-01-11 15:30:03 -0800849// --------- XMLComment ---------- //
850
Lee Thomasone4422302012-01-20 17:59:50 -0800851XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800852{
853}
854
855
Lee Thomasonce0763e2012-01-11 15:43:54 -0800856XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800857{
Lee Thomasond923c672012-01-23 08:44:25 -0800858 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800859}
860
861
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800862char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800863{
864 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800865 const char* start = p;
866 p = value.ParseText( p, "-->", StrPair::COMMENT );
867 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700868 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800869 }
870 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800871}
872
873
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800874XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
875{
876 if ( !doc ) {
877 doc = document;
878 }
879 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
880 return comment;
881}
882
883
884bool XMLComment::ShallowEqual( const XMLNode* compare ) const
885{
886 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
887}
888
889
Lee Thomason751da522012-02-10 08:50:51 -0800890bool XMLComment::Accept( XMLVisitor* visitor ) const
891{
892 return visitor->Visit( *this );
893}
Lee Thomason56bdd022012-02-09 18:16:58 -0800894
895
Lee Thomason50f97b22012-02-11 16:33:40 -0800896// --------- XMLDeclaration ---------- //
897
898XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
899{
900}
901
902
903XMLDeclaration::~XMLDeclaration()
904{
905 //printf( "~XMLDeclaration\n" );
906}
907
908
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800909char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800910{
911 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800912 const char* start = p;
913 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
914 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700915 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800916 }
917 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800918}
919
920
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800921XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
922{
923 if ( !doc ) {
924 doc = document;
925 }
926 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
927 return dec;
928}
929
930
931bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
932{
933 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
934}
935
936
937
Lee Thomason50f97b22012-02-11 16:33:40 -0800938bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
939{
940 return visitor->Visit( *this );
941}
942
943// --------- XMLUnknown ---------- //
944
945XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
946{
947}
948
949
950XMLUnknown::~XMLUnknown()
951{
952}
953
954
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800955char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800956{
957 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800958 const char* start = p;
959
960 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
961 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700962 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800963 }
964 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800965}
966
967
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800968XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
969{
970 if ( !doc ) {
971 doc = document;
972 }
973 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
974 return text;
975}
976
977
978bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
979{
980 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
981}
982
983
Lee Thomason50f97b22012-02-11 16:33:40 -0800984bool XMLUnknown::Accept( XMLVisitor* visitor ) const
985{
986 return visitor->Visit( *this );
987}
988
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800989// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -0800990char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800991{
Lee Thomason78a773d2012-07-02 10:10:19 -0700992 // Parse using the name rules: bug fix, was using ParseText before
993 p = name.ParseName( p );
Lee Thomason22aead12012-01-23 13:29:35 -0800994 if ( !p || !*p ) return 0;
995
Lee Thomason78a773d2012-07-02 10:10:19 -0700996 // Skip white space before =
997 p = XMLUtil::SkipWhiteSpace( p );
998 if ( !p || *p != '=' ) return 0;
999
1000 ++p; // move up to opening quote
1001 p = XMLUtil::SkipWhiteSpace( p );
1002 if ( *p != '\"' && *p != '\'' ) return 0;
1003
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001004 char endTag[2] = { *p, 0 };
Lee Thomason78a773d2012-07-02 10:10:19 -07001005 ++p; // move past opening quote
1006
Lee Thomason6f381b72012-03-02 12:59:39 -08001007 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001008 return p;
1009}
1010
1011
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001012void XMLAttribute::SetName( const char* n )
1013{
1014 name.SetStr( n );
1015}
1016
1017
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001018int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001019{
Lee Thomason21be8822012-07-15 17:27:22 -07001020 if ( XMLUtil::ToInt( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001021 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001022 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001023}
1024
1025
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001026int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001027{
Lee Thomason21be8822012-07-15 17:27:22 -07001028 if ( XMLUtil::ToUnsigned( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001029 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001030 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001031}
1032
1033
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001034int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001035{
Lee Thomason21be8822012-07-15 17:27:22 -07001036 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001037 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001038 }
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001039 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001040}
1041
1042
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001044{
Lee Thomason21be8822012-07-15 17:27:22 -07001045 if ( XMLUtil::ToFloat( Value(), value ))
1046 return XML_NO_ERROR;
1047 return XML_WRONG_ATTRIBUTE_TYPE;
1048}
1049
1050
1051int XMLAttribute::QueryDoubleValue( double* value ) const
1052{
1053 if ( XMLUtil::ToDouble( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001054 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001055 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001056}
1057
1058
1059void XMLAttribute::SetAttribute( const char* v )
1060{
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001061 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001062}
1063
1064
Lee Thomason1ff38e02012-02-14 18:18:16 -08001065void XMLAttribute::SetAttribute( int v )
1066{
1067 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001068 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001069 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001070}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001071
1072
1073void XMLAttribute::SetAttribute( unsigned v )
1074{
1075 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001076 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001077 value.SetStr( buf );
1078}
1079
1080
1081void XMLAttribute::SetAttribute( bool v )
1082{
1083 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001084 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001085 value.SetStr( buf );
1086}
1087
1088void XMLAttribute::SetAttribute( double v )
1089{
1090 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001091 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001092 value.SetStr( buf );
1093}
1094
1095void XMLAttribute::SetAttribute( float v )
1096{
1097 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001098 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001099 value.SetStr( buf );
1100}
1101
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001102
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103// --------- XMLElement ---------- //
1104XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001105 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001107{
1108}
1109
1110
1111XMLElement::~XMLElement()
1112{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001113 while( rootAttribute ) {
1114 XMLAttribute* next = rootAttribute->next;
1115 DELETE_ATTRIBUTE( rootAttribute );
1116 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001117 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001118}
1119
1120
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001121XMLAttribute* XMLElement::FindAttribute( const char* name )
1122{
1123 XMLAttribute* a = 0;
1124 for( a=rootAttribute; a; a = a->next ) {
1125 if ( XMLUtil::StringEqual( a->Name(), name ) )
1126 return a;
1127 }
1128 return 0;
1129}
1130
1131
1132const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1133{
1134 XMLAttribute* a = 0;
1135 for( a=rootAttribute; a; a = a->next ) {
1136 if ( XMLUtil::StringEqual( a->Name(), name ) )
1137 return a;
1138 }
1139 return 0;
1140}
1141
1142
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001143const char* XMLElement::Attribute( const char* name, const char* value ) const
1144{
1145 const XMLAttribute* a = FindAttribute( name );
1146 if ( !a )
1147 return 0;
1148 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1149 return a->Value();
1150 return 0;
1151}
1152
1153
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001154const char* XMLElement::GetText() const
1155{
1156 if ( FirstChild() && FirstChild()->ToText() ) {
1157 return FirstChild()->ToText()->Value();
1158 }
1159 return 0;
1160}
1161
1162
Lee Thomason21be8822012-07-15 17:27:22 -07001163int XMLElement::QueryIntText( int* _value ) const
1164{
1165 if ( FirstChild() && FirstChild()->ToText() ) {
1166 const char* t = FirstChild()->ToText()->Value();
1167 if ( XMLUtil::ToInt( t, _value ) ) {
1168 return XML_SUCCESS;
1169 }
1170 return XML_CAN_NOT_CONVERT_TEXT;
1171 }
1172 return XML_NO_TEXT_NODE;
1173}
1174
1175
1176int XMLElement::QueryUnsignedText( unsigned* _value ) const
1177{
1178 if ( FirstChild() && FirstChild()->ToText() ) {
1179 const char* t = FirstChild()->ToText()->Value();
1180 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1181 return XML_SUCCESS;
1182 }
1183 return XML_CAN_NOT_CONVERT_TEXT;
1184 }
1185 return XML_NO_TEXT_NODE;
1186}
1187
1188
1189int XMLElement::QueryBoolText( bool* _value ) const
1190{
1191 if ( FirstChild() && FirstChild()->ToText() ) {
1192 const char* t = FirstChild()->ToText()->Value();
1193 if ( XMLUtil::ToBool( t, _value ) ) {
1194 return XML_SUCCESS;
1195 }
1196 return XML_CAN_NOT_CONVERT_TEXT;
1197 }
1198 return XML_NO_TEXT_NODE;
1199}
1200
1201
1202int XMLElement::QueryDoubleText( double* _value ) const
1203{
1204 if ( FirstChild() && FirstChild()->ToText() ) {
1205 const char* t = FirstChild()->ToText()->Value();
1206 if ( XMLUtil::ToDouble( t, _value ) ) {
1207 return XML_SUCCESS;
1208 }
1209 return XML_CAN_NOT_CONVERT_TEXT;
1210 }
1211 return XML_NO_TEXT_NODE;
1212}
1213
1214
1215int XMLElement::QueryFloatText( float* _value ) const
1216{
1217 if ( FirstChild() && FirstChild()->ToText() ) {
1218 const char* t = FirstChild()->ToText()->Value();
1219 if ( XMLUtil::ToFloat( t, _value ) ) {
1220 return XML_SUCCESS;
1221 }
1222 return XML_CAN_NOT_CONVERT_TEXT;
1223 }
1224 return XML_NO_TEXT_NODE;
1225}
1226
1227
1228
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1230{
Lee Thomason5e3803c2012-04-16 08:57:05 -07001231 XMLAttribute* last = 0;
1232 XMLAttribute* attrib = 0;
1233 for( attrib = rootAttribute;
1234 attrib;
1235 last = attrib, attrib = attrib->next )
1236 {
1237 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1238 break;
1239 }
1240 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001242 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001243 attrib->memPool = &document->attributePool;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001244 if ( last ) {
1245 last->next = attrib;
1246 }
1247 else {
1248 rootAttribute = attrib;
1249 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001250 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001251 }
1252 return attrib;
1253}
1254
1255
U-Stream\Leeae25a442012-02-17 17:48:16 -08001256void XMLElement::DeleteAttribute( const char* name )
1257{
1258 XMLAttribute* prev = 0;
1259 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1260 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1261 if ( prev ) {
1262 prev->next = a->next;
1263 }
1264 else {
1265 rootAttribute = a->next;
1266 }
1267 DELETE_ATTRIBUTE( a );
1268 break;
1269 }
1270 prev = a;
1271 }
1272}
1273
1274
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001275char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001276{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001277 const char* start = p;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001278 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001279
1280 // Read the attributes.
1281 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001282 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001283 if ( !p || !(*p) ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001284 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001285 return 0;
1286 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001287
1288 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001289 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001290 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001291 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001292
Lee Thomason6f381b72012-03-02 12:59:39 -08001293 p = attrib->ParseDeep( p, document->ProcessEntities() );
Lee Thomasond6277762012-02-22 16:00:12 -08001294 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001295 DELETE_ATTRIBUTE( attrib );
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001296 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001297 return 0;
1298 }
Lee Thomason5e3803c2012-04-16 08:57:05 -07001299 // There is a minor bug here: if the attribute in the source xml
1300 // document is duplicated, it will not be detected and the
1301 // attribute will be doubly added. However, tracking the 'prevAttribute'
1302 // avoids re-scanning the attribute list. Preferring performance for
1303 // now, may reconsider in the future.
1304 if ( prevAttribute ) {
1305 prevAttribute->next = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001306 }
1307 else {
1308 rootAttribute = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001309 }
Lee Thomason97088852012-04-18 11:39:42 -07001310 prevAttribute = attrib;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001311 }
Lee Thomasone4422302012-01-20 17:59:50 -08001312 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001313 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001314 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001315 return p+2; // done; sealed element.
1316 }
Lee Thomasone4422302012-01-20 17:59:50 -08001317 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001318 else if ( *p == '>' ) {
1319 ++p;
1320 break;
1321 }
Lee Thomasone4422302012-01-20 17:59:50 -08001322 else {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001323 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001324 return 0;
1325 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001326 }
Lee Thomason67d61312012-01-24 16:01:51 -08001327 return p;
1328}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001329
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001330
Lee Thomason67d61312012-01-24 16:01:51 -08001331//
1332// <ele></ele>
1333// <ele>foo<b>bar</b></ele>
1334//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001335char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001336{
1337 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001338 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001339 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001340
1341 // The closing element is the </element> form. It is
1342 // parsed just like a regular element then deleted from
1343 // the DOM.
1344 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001345 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001346 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347 }
Lee Thomason67d61312012-01-24 16:01:51 -08001348
Lee Thomason56bdd022012-02-09 18:16:58 -08001349 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001350 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001351
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001352 p = ParseAttributes( p );
1353 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001354 return p;
1355
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001356 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001357 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001358}
1359
1360
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001361
1362XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1363{
1364 if ( !doc ) {
1365 doc = document;
1366 }
1367 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1368 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1369 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1370 }
1371 return element;
1372}
1373
1374
1375bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1376{
1377 const XMLElement* other = compare->ToElement();
1378 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1379
1380 const XMLAttribute* a=FirstAttribute();
1381 const XMLAttribute* b=other->FirstAttribute();
1382
1383 while ( a && b ) {
1384 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1385 return false;
1386 }
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001387 a = a->Next();
1388 b = b->Next();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001389 }
1390 if ( a || b ) {
1391 // different count
1392 return false;
1393 }
1394 return true;
1395 }
1396 return false;
1397}
1398
1399
Lee Thomason751da522012-02-10 08:50:51 -08001400bool XMLElement::Accept( XMLVisitor* visitor ) const
1401{
1402 if ( visitor->VisitEnter( *this, rootAttribute ) )
1403 {
1404 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1405 {
1406 if ( !node->Accept( visitor ) )
1407 break;
1408 }
1409 }
1410 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001411}
Lee Thomason56bdd022012-02-09 18:16:58 -08001412
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001413
Lee Thomason3f57d272012-01-11 15:30:03 -08001414// --------- XMLDocument ----------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001415XMLDocument::XMLDocument( bool _processEntities ) :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001416 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001417 writeBOM( false ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001418 processEntities( _processEntities ),
1419 errorID( 0 ),
1420 errorStr1( 0 ),
1421 errorStr2( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001422 charBuffer( 0 )
1423{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001424 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001425}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001426
1427
Lee Thomason3f57d272012-01-11 15:30:03 -08001428XMLDocument::~XMLDocument()
1429{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001430 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001431 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001432
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001433#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001434 textPool.Trace( "text" );
1435 elementPool.Trace( "element" );
1436 commentPool.Trace( "comment" );
1437 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001438#endif
1439
Lee Thomason455c9d42012-02-06 09:14:14 -08001440 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1441 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1442 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1443 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001444}
1445
1446
Lee Thomason18d68bd2012-01-26 18:17:26 -08001447void XMLDocument::InitDocument()
1448{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001449 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001450 errorStr1 = 0;
1451 errorStr2 = 0;
1452
1453 delete [] charBuffer;
1454 charBuffer = 0;
1455
1456}
1457
Lee Thomason3f57d272012-01-11 15:30:03 -08001458
Lee Thomason2c85a712012-01-31 08:24:24 -08001459XMLElement* XMLDocument::NewElement( const char* name )
1460{
Lee Thomasond1983222012-02-06 08:41:24 -08001461 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1462 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001463 ele->SetName( name );
1464 return ele;
1465}
1466
1467
Lee Thomason1ff38e02012-02-14 18:18:16 -08001468XMLComment* XMLDocument::NewComment( const char* str )
1469{
1470 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1471 comment->memPool = &commentPool;
1472 comment->SetValue( str );
1473 return comment;
1474}
1475
1476
1477XMLText* XMLDocument::NewText( const char* str )
1478{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001479 XMLText* text = new (textPool.Alloc()) XMLText( this );
1480 text->memPool = &textPool;
1481 text->SetValue( str );
1482 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001483}
1484
1485
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001486XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1487{
1488 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1489 dec->memPool = &commentPool;
Lee Thomasonf68c4382012-04-28 14:37:11 -07001490 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001491 return dec;
1492}
1493
1494
1495XMLUnknown* XMLDocument::NewUnknown( const char* str )
1496{
1497 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1498 unk->memPool = &commentPool;
1499 unk->SetValue( str );
1500 return unk;
1501}
1502
1503
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001504int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001505{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001506 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001507 InitDocument();
1508
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001509#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001510#pragma warning ( push )
1511#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001512#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001513 FILE* fp = fopen( filename, "rb" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001514#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001515#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001516#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001517 if ( !fp ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001518 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001519 return errorID;
1520 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001521 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001522 fclose( fp );
1523 return errorID;
1524}
1525
1526
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001527int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001528{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001529 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001530 InitDocument();
1531
1532 fseek( fp, 0, SEEK_END );
1533 unsigned size = ftell( fp );
1534 fseek( fp, 0, SEEK_SET );
1535
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001536 if ( size == 0 ) {
1537 return errorID;
1538 }
1539
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001540 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001541 size_t read = fread( charBuffer, 1, size, fp );
1542 if ( read != size ) {
1543 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1544 return errorID;
1545 }
1546
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001547 charBuffer[size] = 0;
1548
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001549 const char* p = charBuffer;
1550 p = XMLUtil::SkipWhiteSpace( p );
1551 p = XMLUtil::ReadBOM( p, &writeBOM );
1552 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001553 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001554 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001555 }
1556
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001557 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001558 return errorID;
1559}
1560
1561
Robert Reif312a20f2012-09-08 19:33:57 -04001562int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001563{
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001564#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001565#pragma warning ( push )
1566#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001567#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001568 FILE* fp = fopen( filename, "w" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001570#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571#endif
Ken Miller81da1fb2012-04-09 23:32:26 -05001572 if ( !fp ) {
Lee Thomason7f7b1622012-03-24 12:49:03 -07001573 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001574 return errorID;
Lee Thomason7f7b1622012-03-24 12:49:03 -07001575 }
Robert Reif312a20f2012-09-08 19:33:57 -04001576 SaveFile(fp, compact);
Ken Miller81da1fb2012-04-09 23:32:26 -05001577 fclose( fp );
1578 return errorID;
1579}
1580
1581
Robert Reif312a20f2012-09-08 19:33:57 -04001582int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001583{
Robert Reif312a20f2012-09-08 19:33:57 -04001584 XMLPrinter stream( fp, compact );
Ken Miller81da1fb2012-04-09 23:32:26 -05001585 Print( &stream );
1586 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001587}
1588
Lee Thomason1ff38e02012-02-14 18:18:16 -08001589
Lee Thomason7c913cd2012-01-26 18:32:34 -08001590int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001591{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001592 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001593 InitDocument();
1594
1595 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001596 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001597 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001598 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001599 p = XMLUtil::SkipWhiteSpace( p );
1600 p = XMLUtil::ReadBOM( p, &writeBOM );
1601 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001602 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001603 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001604 }
1605
Lee Thomason18d68bd2012-01-26 18:17:26 -08001606 size_t len = strlen( p );
1607 charBuffer = new char[ len+1 ];
1608 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001609
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001610
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001611 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001612 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001613}
1614
1615
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001616void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001617{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001618 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001619 if ( !streamer )
1620 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001621 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001622}
1623
1624
Lee Thomason67d61312012-01-24 16:01:51 -08001625void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1626{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001627 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001628 errorStr1 = str1;
1629 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001630}
1631
Lee Thomason5cae8972012-01-24 18:03:07 -08001632
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001633void XMLDocument::PrintError() const
1634{
1635 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001636 static const int LEN = 20;
1637 char buf1[LEN] = { 0 };
1638 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001639
1640 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001641 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001642 }
1643 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001644 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001645 }
1646
1647 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1648 errorID, buf1, buf2 );
1649 }
1650}
1651
1652
sniperbat25900882012-05-28 17:22:07 +08001653XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001654 elementJustOpened( false ),
1655 firstElement( true ),
1656 fp( file ),
1657 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001658 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001659 processEntities( true ),
1660 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001661{
Lee Thomason857b8682012-01-25 17:50:25 -08001662 for( int i=0; i<ENTITY_RANGE; ++i ) {
1663 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001664 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001665 }
1666 for( int i=0; i<NUM_ENTITIES; ++i ) {
1667 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1668 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001669 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001670 }
1671 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001672 restrictedEntityFlag[(int)'&'] = true;
1673 restrictedEntityFlag[(int)'<'] = true;
1674 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001675 buffer.Push( 0 );
1676}
1677
1678
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001679void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001680{
1681 va_list va;
1682 va_start( va, format );
1683
1684 if ( fp ) {
1685 vfprintf( fp, format, va );
1686 }
1687 else {
1688 // This seems brutally complex. Haven't figured out a better
1689 // way on windows.
1690 #ifdef _MSC_VER
1691 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001692 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001693 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001694 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001695 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001696 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001697 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001698 }
1699 }
1700 char* p = buffer.PushArr( len ) - 1;
1701 memcpy( p, accumulator.Mem(), len+1 );
1702 #else
1703 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001704 // Close out and re-start the va-args
1705 va_end( va );
1706 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001707 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001708 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001709 #endif
1710 }
1711 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001712}
1713
1714
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001715void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001716{
1717 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001718 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001719 }
1720}
1721
1722
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001723void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001724{
Lee Thomason951d8832012-01-26 08:47:06 -08001725 // Look for runs of bytes between entities to print.
1726 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001728
Lee Thomason6f381b72012-03-02 12:59:39 -08001729 if ( processEntities ) {
1730 while ( *q ) {
1731 // Remember, char is sometimes signed. (How many times has that bitten me?)
1732 if ( *q > 0 && *q < ENTITY_RANGE ) {
1733 // Check for entities. If one is found, flush
1734 // the stream up until the entity, write the
1735 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001736 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001737 while ( p < q ) {
1738 Print( "%c", *p );
1739 ++p;
1740 }
1741 for( int i=0; i<NUM_ENTITIES; ++i ) {
1742 if ( entities[i].value == *q ) {
1743 Print( "&%s;", entities[i].pattern );
1744 break;
1745 }
1746 }
Lee Thomason951d8832012-01-26 08:47:06 -08001747 ++p;
1748 }
Lee Thomason951d8832012-01-26 08:47:06 -08001749 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001750 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001751 }
Lee Thomason951d8832012-01-26 08:47:06 -08001752 }
1753 // Flush the remaining string. This will be the entire
1754 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001755 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001756 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001757 }
Lee Thomason857b8682012-01-25 17:50:25 -08001758}
1759
U-Stream\Leeae25a442012-02-17 17:48:16 -08001760
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001761void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001762{
1763 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1764 if ( writeBOM ) {
1765 Print( "%s", bom );
1766 }
1767 if ( writeDec ) {
1768 PushDeclaration( "xml version=\"1.0\"" );
1769 }
1770}
1771
1772
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001773void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001774{
1775 if ( elementJustOpened ) {
1776 SealElement();
1777 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001778 stack.Push( name );
1779
sniperbat25900882012-05-28 17:22:07 +08001780 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001781 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001782 PrintSpace( depth );
1783 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001784
U-Stream\Leeae25a442012-02-17 17:48:16 -08001785 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001786 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001787 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001788 ++depth;
1789}
1790
1791
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001792void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001793{
1794 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001795 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001797 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001798}
1799
1800
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001801void XMLPrinter::PushAttribute( const char* name, int v )
1802{
1803 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001804 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001805 PushAttribute( name, buf );
1806}
1807
1808
1809void XMLPrinter::PushAttribute( const char* name, unsigned v )
1810{
1811 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001812 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001813 PushAttribute( name, buf );
1814}
1815
1816
1817void XMLPrinter::PushAttribute( const char* name, bool v )
1818{
1819 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001820 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001821 PushAttribute( name, buf );
1822}
1823
1824
1825void XMLPrinter::PushAttribute( const char* name, double v )
1826{
1827 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001828 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001829 PushAttribute( name, buf );
1830}
1831
1832
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001833void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001834{
1835 --depth;
1836 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001837
1838 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001839 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001840 }
1841 else {
sniperbat25900882012-05-28 17:22:07 +08001842 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001843 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001844 PrintSpace( depth );
1845 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001846 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001847 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001848
1849 if ( textDepth == depth )
1850 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001851 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001852 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001853 elementJustOpened = false;
1854}
1855
1856
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001857void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001858{
1859 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001860 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001861}
1862
1863
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001864void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001865{
Lee Thomason56bdd022012-02-09 18:16:58 -08001866 textDepth = depth-1;
1867
Lee Thomason5cae8972012-01-24 18:03:07 -08001868 if ( elementJustOpened ) {
1869 SealElement();
1870 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001871 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001872 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001873 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001874 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001875 }
1876 else {
1877 PrintString( text, true );
1878 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001879}
1880
Lee Thomason21be8822012-07-15 17:27:22 -07001881void XMLPrinter::PushText( int value )
1882{
1883 char buf[BUF_SIZE];
1884 XMLUtil::ToStr( value, buf, BUF_SIZE );
1885 PushText( buf, false );
1886}
1887
1888
1889void XMLPrinter::PushText( unsigned value )
1890{
1891 char buf[BUF_SIZE];
1892 XMLUtil::ToStr( value, buf, BUF_SIZE );
1893 PushText( buf, false );
1894}
1895
1896
1897void XMLPrinter::PushText( bool value )
1898{
1899 char buf[BUF_SIZE];
1900 XMLUtil::ToStr( value, buf, BUF_SIZE );
1901 PushText( buf, false );
1902}
1903
1904
1905void XMLPrinter::PushText( float value )
1906{
1907 char buf[BUF_SIZE];
1908 XMLUtil::ToStr( value, buf, BUF_SIZE );
1909 PushText( buf, false );
1910}
1911
1912
1913void XMLPrinter::PushText( double value )
1914{
1915 char buf[BUF_SIZE];
1916 XMLUtil::ToStr( value, buf, BUF_SIZE );
1917 PushText( buf, false );
1918}
1919
Lee Thomason5cae8972012-01-24 18:03:07 -08001920
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001921void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001922{
1923 if ( elementJustOpened ) {
1924 SealElement();
1925 }
sniperbat25900882012-05-28 17:22:07 +08001926 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001927 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001928 PrintSpace( depth );
1929 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001930 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001931 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001932}
Lee Thomason751da522012-02-10 08:50:51 -08001933
1934
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001935void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001936{
1937 if ( elementJustOpened ) {
1938 SealElement();
1939 }
sniperbat25900882012-05-28 17:22:07 +08001940 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941 Print( "\n" );
1942 PrintSpace( depth );
1943 }
1944 firstElement = false;
1945 Print( "<?%s?>", value );
1946}
1947
1948
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001949void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001950{
1951 if ( elementJustOpened ) {
1952 SealElement();
1953 }
sniperbat25900882012-05-28 17:22:07 +08001954 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955 Print( "\n" );
1956 PrintSpace( depth );
1957 }
1958 firstElement = false;
1959 Print( "<!%s>", value );
1960}
1961
1962
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001963bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001964{
Lee Thomason6f381b72012-03-02 12:59:39 -08001965 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001966 if ( doc.HasBOM() ) {
1967 PushHeader( true, false );
1968 }
1969 return true;
1970}
1971
1972
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001973bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001974{
1975 OpenElement( element.Name() );
1976 while ( attribute ) {
1977 PushAttribute( attribute->Name(), attribute->Value() );
1978 attribute = attribute->Next();
1979 }
1980 return true;
1981}
1982
1983
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001984bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08001985{
1986 CloseElement();
1987 return true;
1988}
1989
1990
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001991bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001992{
Lee Thomasond6277762012-02-22 16:00:12 -08001993 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001994 return true;
1995}
1996
1997
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001998bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08001999{
2000 PushComment( comment.Value() );
2001 return true;
2002}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002003
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002004bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002005{
2006 PushDeclaration( declaration.Value() );
2007 return true;
2008}
2009
2010
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002011bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002012{
2013 PushUnknown( unknown.Value() );
2014 return true;
2015}