blob: b7dd909bb401a851eed266c56d2a8559288a225b [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 == '&' ) {
193 int i=0;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800194
195 // Entities handled by tinyXML2:
196 // - special entities in the entity table [in/out]
197 // - numeric character reference [in]
198 // &#20013; or &#x4e2d;
199
200 if ( *(p+1) == '#' ) {
201 char buf[10] = { 0 };
202 int len;
203 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
204 for( int i=0; i<len; ++i ) {
205 *q++ = buf[i];
Lee Thomason8ee79892012-01-25 17:44:30 -0800206 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800207 TIXMLASSERT( q <= p );
Lee Thomason8ee79892012-01-25 17:44:30 -0800208 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800209 else {
210 for( i=0; i<NUM_ENTITIES; ++i ) {
211 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
212 && *(p+entities[i].length+1) == ';' )
213 {
214 // Found an entity convert;
215 *q = entities[i].value;
216 ++q;
217 p += entities[i].length + 2;
218 break;
219 }
220 }
221 if ( i == NUM_ENTITIES ) {
222 // fixme: treat as error?
223 ++p;
224 ++q;
225 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800226 }
227 }
Lee Thomasone4422302012-01-20 17:59:50 -0800228 else {
229 *q = *p;
230 ++p;
Lee Thomasonec975ce2012-01-23 11:42:06 -0800231 ++q;
Lee Thomasone4422302012-01-20 17:59:50 -0800232 }
233 }
Lee Thomason8ee79892012-01-25 17:44:30 -0800234 *q = 0;
Lee Thomasone4422302012-01-20 17:59:50 -0800235 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800236 flags = (flags & NEEDS_DELETE);
Lee Thomasone4422302012-01-20 17:59:50 -0800237 }
238 return start;
239}
240
Lee Thomason2c85a712012-01-31 08:24:24 -0800241
Lee Thomasone4422302012-01-20 17:59:50 -0800242
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800243
Lee Thomason56bdd022012-02-09 18:16:58 -0800244// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800245
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800246const char* XMLUtil::ReadBOM( const char* p, bool* bom )
247{
248 *bom = false;
249 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
250 // Check for BOM:
251 if ( *(pu+0) == TIXML_UTF_LEAD_0
252 && *(pu+1) == TIXML_UTF_LEAD_1
253 && *(pu+2) == TIXML_UTF_LEAD_2 )
254 {
255 *bom = true;
256 p += 3;
257 }
258 return p;
259}
260
261
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800262void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
263{
264 const unsigned long BYTE_MASK = 0xBF;
265 const unsigned long BYTE_MARK = 0x80;
266 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
267
268 if (input < 0x80)
269 *length = 1;
270 else if ( input < 0x800 )
271 *length = 2;
272 else if ( input < 0x10000 )
273 *length = 3;
274 else if ( input < 0x200000 )
275 *length = 4;
276 else
277 { *length = 0; return; } // This code won't covert this correctly anyway.
278
279 output += *length;
280
281 // Scary scary fall throughs.
282 switch (*length)
283 {
284 case 4:
285 --output;
286 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
287 input >>= 6;
288 case 3:
289 --output;
290 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
291 input >>= 6;
292 case 2:
293 --output;
294 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
295 input >>= 6;
296 case 1:
297 --output;
298 *output = (char)(input | FIRST_BYTE_MARK[*length]);
299 }
300}
301
302
303const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
304{
305 // Presume an entity, and pull it out.
306 *length = 0;
307
308 if ( *(p+1) == '#' && *(p+2) )
309 {
310 unsigned long ucs = 0;
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200311 ptrdiff_t delta = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800312 unsigned mult = 1;
313
314 if ( *(p+2) == 'x' )
315 {
316 // Hexadecimal.
317 if ( !*(p+3) ) return 0;
318
319 const char* q = p+3;
320 q = strchr( q, ';' );
321
322 if ( !q || !*q ) return 0;
323
Thomas Roß7d7a9a32012-05-10 00:23:19 +0200324 delta = q-p;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800325 --q;
326
327 while ( *q != 'x' )
328 {
329 if ( *q >= '0' && *q <= '9' )
330 ucs += mult * (*q - '0');
331 else if ( *q >= 'a' && *q <= 'f' )
332 ucs += mult * (*q - 'a' + 10);
333 else if ( *q >= 'A' && *q <= 'F' )
334 ucs += mult * (*q - 'A' + 10 );
335 else
336 return 0;
337 mult *= 16;
338 --q;
339 }
340 }
341 else
342 {
343 // Decimal.
344 if ( !*(p+2) ) return 0;
345
346 const char* q = p+2;
347 q = strchr( q, ';' );
348
349 if ( !q || !*q ) return 0;
350
351 delta = q-p;
352 --q;
353
354 while ( *q != '#' )
355 {
356 if ( *q >= '0' && *q <= '9' )
357 ucs += mult * (*q - '0');
358 else
359 return 0;
360 mult *= 10;
361 --q;
362 }
363 }
364 // convert the UCS to UTF-8
365 ConvertUTF32ToUTF8( ucs, value, length );
366 return p + delta + 1;
367 }
368 return p+1;
369}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800370
371
Lee Thomason21be8822012-07-15 17:27:22 -0700372void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
373{
374 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
375}
376
377
378void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
379{
380 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
381}
382
383
384void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
385{
386 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
387}
388
389
390void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
391{
392 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
393}
394
395
396void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
397{
398 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
399}
400
401
402bool XMLUtil::ToInt( const char* str, int* value )
403{
404 if ( TIXML_SSCANF( str, "%d", value ) == 1 )
405 return true;
406 return false;
407}
408
409bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
410{
411 if ( TIXML_SSCANF( str, "%u", value ) == 1 )
412 return true;
413 return false;
414}
415
416bool XMLUtil::ToBool( const char* str, bool* value )
417{
418 int ival = 0;
419 if ( ToInt( str, &ival )) {
420 *value = (ival==0) ? false : true;
421 return true;
422 }
423 if ( StringEqual( str, "true" ) ) {
424 *value = true;
425 return true;
426 }
427 else if ( StringEqual( str, "false" ) ) {
428 *value = false;
429 return true;
430 }
431 return false;
432}
433
434
435bool XMLUtil::ToFloat( const char* str, float* value )
436{
437 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
438 return true;
439 }
440 return false;
441}
442
443bool XMLUtil::ToDouble( const char* str, double* value )
444{
445 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
446 return true;
447 }
448 return false;
449}
450
451
Lee Thomasond1983222012-02-06 08:41:24 -0800452char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800453{
454 XMLNode* returnNode = 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800455 char* start = p;
Lee Thomason56bdd022012-02-09 18:16:58 -0800456 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason5492a1c2012-01-23 15:32:10 -0800457 if( !p || !*p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800458 {
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800459 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800460 }
461
462 // What is this thing?
463 // - Elements start with a letter or underscore, but xml is reserved.
464 // - Comments: <!--
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800465 // - Decleration: <?
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800466 // - Everthing else is unknown to tinyxml.
467 //
468
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800469 static const char* xmlHeader = { "<?" };
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800470 static const char* commentHeader = { "<!--" };
471 static const char* dtdHeader = { "<!" };
472 static const char* cdataHeader = { "<![CDATA[" };
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800473 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800474
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800475 static const int xmlHeaderLen = 2;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800476 static const int commentHeaderLen = 4;
477 static const int dtdHeaderLen = 2;
478 static const int cdataHeaderLen = 9;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800479 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800480
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800481#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800482#pragma warning ( push )
483#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800484#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800485 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
486 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800487#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800488#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800489#endif
Lee Thomason50f97b22012-02-11 16:33:40 -0800490 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
491 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
492 returnNode->memPool = &commentPool;
493 p += xmlHeaderLen;
494 }
495 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800496 returnNode = new (commentPool.Alloc()) XMLComment( this );
497 returnNode->memPool = &commentPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800498 p += commentHeaderLen;
499 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800500 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
501 XMLText* text = new (textPool.Alloc()) XMLText( this );
502 returnNode = text;
503 returnNode->memPool = &textPool;
504 p += cdataHeaderLen;
505 text->SetCData( true );
506 }
507 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
508 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
509 returnNode->memPool = &commentPool;
510 p += dtdHeaderLen;
511 }
Lee Thomason56bdd022012-02-09 18:16:58 -0800512 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomasond1983222012-02-06 08:41:24 -0800513 returnNode = new (elementPool.Alloc()) XMLElement( this );
514 returnNode->memPool = &elementPool;
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800515 p += elementHeaderLen;
516 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800517 else {
Lee Thomasond1983222012-02-06 08:41:24 -0800518 returnNode = new (textPool.Alloc()) XMLText( this );
519 returnNode->memPool = &textPool;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800520 p = start; // Back it up, all the text counts.
521 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800522
523 *node = returnNode;
524 return p;
525}
526
527
Lee Thomason751da522012-02-10 08:50:51 -0800528bool XMLDocument::Accept( XMLVisitor* visitor ) const
529{
530 if ( visitor->VisitEnter( *this ) )
531 {
532 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
533 {
534 if ( !node->Accept( visitor ) )
535 break;
536 }
537 }
538 return visitor->VisitExit( *this );
539}
Lee Thomason56bdd022012-02-09 18:16:58 -0800540
541
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800542// --------- XMLNode ----------- //
543
544XMLNode::XMLNode( XMLDocument* doc ) :
545 document( doc ),
546 parent( 0 ),
547 firstChild( 0 ), lastChild( 0 ),
548 prev( 0 ), next( 0 )
549{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800550}
551
552
553XMLNode::~XMLNode()
554{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800555 DeleteChildren();
Lee Thomason7c913cd2012-01-26 18:32:34 -0800556 if ( parent ) {
557 parent->Unlink( this );
558 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800559}
560
561
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800562void XMLNode::SetValue( const char* str, bool staticMem )
563{
564 if ( staticMem )
565 value.SetInternedStr( str );
566 else
567 value.SetStr( str );
568}
569
570
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800571void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800572{
Lee Thomasond923c672012-01-23 08:44:25 -0800573 while( firstChild ) {
574 XMLNode* node = firstChild;
575 Unlink( node );
Lee Thomasond1983222012-02-06 08:41:24 -0800576
Lee Thomason43f59302012-02-06 18:18:11 -0800577 DELETE_NODE( node );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800578 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800579 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800580}
581
582
583void XMLNode::Unlink( XMLNode* child )
584{
585 TIXMLASSERT( child->parent == this );
586 if ( child == firstChild )
587 firstChild = firstChild->next;
588 if ( child == lastChild )
589 lastChild = lastChild->prev;
590
591 if ( child->prev ) {
592 child->prev->next = child->next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800593 }
Lee Thomasond923c672012-01-23 08:44:25 -0800594 if ( child->next ) {
595 child->next->prev = child->prev;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596 }
Lee Thomasond923c672012-01-23 08:44:25 -0800597 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800598}
599
600
U-Stream\Leeae25a442012-02-17 17:48:16 -0800601void XMLNode::DeleteChild( XMLNode* node )
602{
603 TIXMLASSERT( node->parent == this );
604 DELETE_NODE( node );
605}
606
607
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800608XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
609{
610 if ( lastChild ) {
611 TIXMLASSERT( firstChild );
612 TIXMLASSERT( lastChild->next == 0 );
613 lastChild->next = addThis;
614 addThis->prev = lastChild;
615 lastChild = addThis;
616
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800617 addThis->next = 0;
618 }
619 else {
620 TIXMLASSERT( firstChild == 0 );
621 firstChild = lastChild = addThis;
622
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800623 addThis->prev = 0;
624 addThis->next = 0;
625 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800626 addThis->parent = this;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627 return addThis;
628}
629
630
Lee Thomason1ff38e02012-02-14 18:18:16 -0800631XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
632{
633 if ( firstChild ) {
634 TIXMLASSERT( lastChild );
635 TIXMLASSERT( firstChild->prev == 0 );
636
637 firstChild->prev = addThis;
638 addThis->next = firstChild;
639 firstChild = addThis;
640
Lee Thomason1ff38e02012-02-14 18:18:16 -0800641 addThis->prev = 0;
642 }
643 else {
644 TIXMLASSERT( lastChild == 0 );
645 firstChild = lastChild = addThis;
646
Lee Thomason1ff38e02012-02-14 18:18:16 -0800647 addThis->prev = 0;
648 addThis->next = 0;
649 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800650 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800651 return addThis;
652}
653
654
655XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
656{
657 TIXMLASSERT( afterThis->parent == this );
658 if ( afterThis->parent != this )
659 return 0;
660
661 if ( afterThis->next == 0 ) {
662 // The last node or the only node.
663 return InsertEndChild( addThis );
664 }
665 addThis->prev = afterThis;
666 addThis->next = afterThis->next;
667 afterThis->next->prev = addThis;
668 afterThis->next = addThis;
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800669 addThis->parent = this;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800670 return addThis;
671}
672
673
674
675
Lee Thomason56bdd022012-02-09 18:16:58 -0800676const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800677{
678 for( XMLNode* node=firstChild; node; node=node->next ) {
679 XMLElement* element = node->ToElement();
680 if ( element ) {
Lee Thomason56bdd022012-02-09 18:16:58 -0800681 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
Lee Thomason2c85a712012-01-31 08:24:24 -0800682 return element;
683 }
684 }
685 }
686 return 0;
687}
688
689
Lee Thomason56bdd022012-02-09 18:16:58 -0800690const XMLElement* XMLNode::LastChildElement( const char* value ) const
691{
692 for( XMLNode* node=lastChild; node; node=node->prev ) {
693 XMLElement* element = node->ToElement();
694 if ( element ) {
695 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
696 return element;
697 }
698 }
699 }
700 return 0;
701}
702
703
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800704const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
705{
706 for( XMLNode* element=this->next; element; element = element->next ) {
707 if ( element->ToElement()
708 && (!value || XMLUtil::StringEqual( value, element->Value() )))
709 {
710 return element->ToElement();
711 }
712 }
713 return 0;
714}
715
716
717const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
718{
719 for( XMLNode* element=this->prev; element; element = element->prev ) {
720 if ( element->ToElement()
721 && (!value || XMLUtil::StringEqual( value, element->Value() )))
722 {
723 return element->ToElement();
724 }
725 }
726 return 0;
727}
728
729
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800730char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800731{
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800732 // This is a recursive method, but thinking about it "at the current level"
733 // it is a pretty simple flat list:
734 // <foo/>
735 // <!-- comment -->
736 //
737 // With a special case:
738 // <foo>
739 // </foo>
740 // <!-- comment -->
741 //
742 // Where the closing element (/foo) *must* be the next thing after the opening
743 // element, and the names must match. BUT the tricky bit is that the closing
744 // element will be read by the child.
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800745 //
746 // 'endTag' is the end tag for this node, it is returned by a call to a child.
747 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800748
Lee Thomason67d61312012-01-24 16:01:51 -0800749 while( p && *p ) {
750 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800751
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800752 p = document->Identify( p, &node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800753 if ( p == 0 || node == 0 ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800754 break;
755 }
756
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800757 StrPair endTag;
758 p = node->ParseDeep( p, &endTag );
759 if ( !p ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800760 DELETE_NODE( node );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800761 node = 0;
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800762 if ( !document->Error() ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700763 document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomason (grinliz)784607f2012-02-24 16:23:40 -0800764 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800765 break;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800766 }
767
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800768 // We read the end tag. Return it to the parent.
769 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
770 if ( parentEnd ) {
771 *parentEnd = ((XMLElement*)node)->value;
Lee Thomason67d61312012-01-24 16:01:51 -0800772 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800773 DELETE_NODE( node );
774 return p;
775 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800776
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800777 // Handle an end tag returned to this level.
778 // And handle a bunch of annoying errors.
779 XMLElement* ele = node->ToElement();
780 if ( ele ) {
781 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700782 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800783 p = 0;
784 }
785 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700786 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800787 p = 0;
788 }
789 else if ( !endTag.Empty() ) {
790 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700791 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800792 p = 0;
793 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800794 }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800795 }
796 if ( p == 0 ) {
797 DELETE_NODE( node );
798 node = 0;
799 }
800 if ( node ) {
801 this->InsertEndChild( node );
Lee Thomason67d61312012-01-24 16:01:51 -0800802 }
803 }
804 return 0;
805}
806
Lee Thomason5492a1c2012-01-23 15:32:10 -0800807// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800808char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800809{
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800810 const char* start = p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800811 if ( this->CData() ) {
812 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800813 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700814 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800815 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800816 return p;
817 }
818 else {
Lee Thomason6f381b72012-03-02 12:59:39 -0800819 p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800820 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700821 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800822 }
Lee Thomason50f97b22012-02-11 16:33:40 -0800823 if ( p && *p ) {
824 return p-1;
825 }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800826 }
827 return 0;
828}
829
830
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800831XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
832{
833 if ( !doc ) {
834 doc = document;
835 }
836 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
837 text->SetCData( this->CData() );
838 return text;
839}
840
841
842bool XMLText::ShallowEqual( const XMLNode* compare ) const
843{
844 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
845}
846
847
Lee Thomason56bdd022012-02-09 18:16:58 -0800848bool XMLText::Accept( XMLVisitor* visitor ) const
849{
850 return visitor->Visit( *this );
851}
852
853
Lee Thomason3f57d272012-01-11 15:30:03 -0800854// --------- XMLComment ---------- //
855
Lee Thomasone4422302012-01-20 17:59:50 -0800856XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800857{
858}
859
860
Lee Thomasonce0763e2012-01-11 15:43:54 -0800861XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800862{
Lee Thomasond923c672012-01-23 08:44:25 -0800863 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800864}
865
866
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800867char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800868{
869 // Comment parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800870 const char* start = p;
871 p = value.ParseText( p, "-->", StrPair::COMMENT );
872 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700873 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800874 }
875 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800876}
877
878
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800879XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
880{
881 if ( !doc ) {
882 doc = document;
883 }
884 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
885 return comment;
886}
887
888
889bool XMLComment::ShallowEqual( const XMLNode* compare ) const
890{
891 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
892}
893
894
Lee Thomason751da522012-02-10 08:50:51 -0800895bool XMLComment::Accept( XMLVisitor* visitor ) const
896{
897 return visitor->Visit( *this );
898}
Lee Thomason56bdd022012-02-09 18:16:58 -0800899
900
Lee Thomason50f97b22012-02-11 16:33:40 -0800901// --------- XMLDeclaration ---------- //
902
903XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
904{
905}
906
907
908XMLDeclaration::~XMLDeclaration()
909{
910 //printf( "~XMLDeclaration\n" );
911}
912
913
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800914char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800915{
916 // Declaration parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800917 const char* start = p;
918 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
919 if ( p == 0 ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700920 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800921 }
922 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800923}
924
925
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800926XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
927{
928 if ( !doc ) {
929 doc = document;
930 }
931 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
932 return dec;
933}
934
935
936bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
937{
938 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
939}
940
941
942
Lee Thomason50f97b22012-02-11 16:33:40 -0800943bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
944{
945 return visitor->Visit( *this );
946}
947
948// --------- XMLUnknown ---------- //
949
950XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
951{
952}
953
954
955XMLUnknown::~XMLUnknown()
956{
957}
958
959
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800960char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800961{
962 // Unknown parses as text.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800963 const char* start = p;
964
965 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
966 if ( !p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700967 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800968 }
969 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800970}
971
972
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
974{
975 if ( !doc ) {
976 doc = document;
977 }
978 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
979 return text;
980}
981
982
983bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
984{
985 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
986}
987
988
Lee Thomason50f97b22012-02-11 16:33:40 -0800989bool XMLUnknown::Accept( XMLVisitor* visitor ) const
990{
991 return visitor->Visit( *this );
992}
993
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800994// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -0800995char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800996{
Lee Thomason78a773d2012-07-02 10:10:19 -0700997 // Parse using the name rules: bug fix, was using ParseText before
998 p = name.ParseName( p );
Lee Thomason22aead12012-01-23 13:29:35 -0800999 if ( !p || !*p ) return 0;
1000
Lee Thomason78a773d2012-07-02 10:10:19 -07001001 // Skip white space before =
1002 p = XMLUtil::SkipWhiteSpace( p );
1003 if ( !p || *p != '=' ) return 0;
1004
1005 ++p; // move up to opening quote
1006 p = XMLUtil::SkipWhiteSpace( p );
1007 if ( *p != '\"' && *p != '\'' ) return 0;
1008
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001009 char endTag[2] = { *p, 0 };
Lee Thomason78a773d2012-07-02 10:10:19 -07001010 ++p; // move past opening quote
1011
Lee Thomason6f381b72012-03-02 12:59:39 -08001012 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001013 return p;
1014}
1015
1016
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001017void XMLAttribute::SetName( const char* n )
1018{
1019 name.SetStr( n );
1020}
1021
1022
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001024{
Lee Thomason21be8822012-07-15 17:27:22 -07001025 if ( XMLUtil::ToInt( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001026 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001027 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001028}
1029
1030
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001031int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001032{
Lee Thomason21be8822012-07-15 17:27:22 -07001033 if ( XMLUtil::ToUnsigned( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001034 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001035 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001036}
1037
1038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001039int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001040{
Lee Thomason21be8822012-07-15 17:27:22 -07001041 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001042 return XML_NO_ERROR;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001043 }
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001044 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001045}
1046
1047
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001048int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001049{
Lee Thomason21be8822012-07-15 17:27:22 -07001050 if ( XMLUtil::ToFloat( Value(), value ))
1051 return XML_NO_ERROR;
1052 return XML_WRONG_ATTRIBUTE_TYPE;
1053}
1054
1055
1056int XMLAttribute::QueryDoubleValue( double* value ) const
1057{
1058 if ( XMLUtil::ToDouble( Value(), value ))
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001059 return XML_NO_ERROR;
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001060 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001061}
1062
1063
1064void XMLAttribute::SetAttribute( const char* v )
1065{
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001066 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001067}
1068
1069
Lee Thomason1ff38e02012-02-14 18:18:16 -08001070void XMLAttribute::SetAttribute( int v )
1071{
1072 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001073 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001074 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001075}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001076
1077
1078void XMLAttribute::SetAttribute( unsigned v )
1079{
1080 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001081 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001082 value.SetStr( buf );
1083}
1084
1085
1086void XMLAttribute::SetAttribute( bool v )
1087{
1088 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001089 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001090 value.SetStr( buf );
1091}
1092
1093void XMLAttribute::SetAttribute( double v )
1094{
1095 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001096 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001097 value.SetStr( buf );
1098}
1099
1100void XMLAttribute::SetAttribute( float v )
1101{
1102 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001103 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001104 value.SetStr( buf );
1105}
1106
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001107
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001108// --------- XMLElement ---------- //
1109XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001110 closingType( 0 ),
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001111 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001112{
1113}
1114
1115
1116XMLElement::~XMLElement()
1117{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001118 while( rootAttribute ) {
1119 XMLAttribute* next = rootAttribute->next;
1120 DELETE_ATTRIBUTE( rootAttribute );
1121 rootAttribute = next;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001122 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001123}
1124
1125
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001126XMLAttribute* XMLElement::FindAttribute( const char* name )
1127{
1128 XMLAttribute* a = 0;
1129 for( a=rootAttribute; a; a = a->next ) {
1130 if ( XMLUtil::StringEqual( a->Name(), name ) )
1131 return a;
1132 }
1133 return 0;
1134}
1135
1136
1137const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1138{
1139 XMLAttribute* a = 0;
1140 for( a=rootAttribute; a; a = a->next ) {
1141 if ( XMLUtil::StringEqual( a->Name(), name ) )
1142 return a;
1143 }
1144 return 0;
1145}
1146
1147
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001148const char* XMLElement::Attribute( const char* name, const char* value ) const
1149{
1150 const XMLAttribute* a = FindAttribute( name );
1151 if ( !a )
1152 return 0;
1153 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1154 return a->Value();
1155 return 0;
1156}
1157
1158
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001159const char* XMLElement::GetText() const
1160{
1161 if ( FirstChild() && FirstChild()->ToText() ) {
1162 return FirstChild()->ToText()->Value();
1163 }
1164 return 0;
1165}
1166
1167
Lee Thomason21be8822012-07-15 17:27:22 -07001168int XMLElement::QueryIntText( int* _value ) const
1169{
1170 if ( FirstChild() && FirstChild()->ToText() ) {
1171 const char* t = FirstChild()->ToText()->Value();
1172 if ( XMLUtil::ToInt( t, _value ) ) {
1173 return XML_SUCCESS;
1174 }
1175 return XML_CAN_NOT_CONVERT_TEXT;
1176 }
1177 return XML_NO_TEXT_NODE;
1178}
1179
1180
1181int XMLElement::QueryUnsignedText( unsigned* _value ) const
1182{
1183 if ( FirstChild() && FirstChild()->ToText() ) {
1184 const char* t = FirstChild()->ToText()->Value();
1185 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1186 return XML_SUCCESS;
1187 }
1188 return XML_CAN_NOT_CONVERT_TEXT;
1189 }
1190 return XML_NO_TEXT_NODE;
1191}
1192
1193
1194int XMLElement::QueryBoolText( bool* _value ) const
1195{
1196 if ( FirstChild() && FirstChild()->ToText() ) {
1197 const char* t = FirstChild()->ToText()->Value();
1198 if ( XMLUtil::ToBool( t, _value ) ) {
1199 return XML_SUCCESS;
1200 }
1201 return XML_CAN_NOT_CONVERT_TEXT;
1202 }
1203 return XML_NO_TEXT_NODE;
1204}
1205
1206
1207int XMLElement::QueryDoubleText( double* _value ) const
1208{
1209 if ( FirstChild() && FirstChild()->ToText() ) {
1210 const char* t = FirstChild()->ToText()->Value();
1211 if ( XMLUtil::ToDouble( t, _value ) ) {
1212 return XML_SUCCESS;
1213 }
1214 return XML_CAN_NOT_CONVERT_TEXT;
1215 }
1216 return XML_NO_TEXT_NODE;
1217}
1218
1219
1220int XMLElement::QueryFloatText( float* _value ) const
1221{
1222 if ( FirstChild() && FirstChild()->ToText() ) {
1223 const char* t = FirstChild()->ToText()->Value();
1224 if ( XMLUtil::ToFloat( t, _value ) ) {
1225 return XML_SUCCESS;
1226 }
1227 return XML_CAN_NOT_CONVERT_TEXT;
1228 }
1229 return XML_NO_TEXT_NODE;
1230}
1231
1232
1233
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001234XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1235{
Lee Thomason5e3803c2012-04-16 08:57:05 -07001236 XMLAttribute* last = 0;
1237 XMLAttribute* attrib = 0;
1238 for( attrib = rootAttribute;
1239 attrib;
1240 last = attrib, attrib = attrib->next )
1241 {
1242 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1243 break;
1244 }
1245 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246 if ( !attrib ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001247 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248 attrib->memPool = &document->attributePool;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001249 if ( last ) {
1250 last->next = attrib;
1251 }
1252 else {
1253 rootAttribute = attrib;
1254 }
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001255 attrib->SetName( name );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001256 }
1257 return attrib;
1258}
1259
1260
U-Stream\Leeae25a442012-02-17 17:48:16 -08001261void XMLElement::DeleteAttribute( const char* name )
1262{
1263 XMLAttribute* prev = 0;
1264 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1265 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1266 if ( prev ) {
1267 prev->next = a->next;
1268 }
1269 else {
1270 rootAttribute = a->next;
1271 }
1272 DELETE_ATTRIBUTE( a );
1273 break;
1274 }
1275 prev = a;
1276 }
1277}
1278
1279
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001280char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001281{
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001282 const char* start = p;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001283 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001284
1285 // Read the attributes.
1286 while( p ) {
Lee Thomason56bdd022012-02-09 18:16:58 -08001287 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001288 if ( !p || !(*p) ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001289 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001290 return 0;
1291 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001292
1293 // attribute.
Lee Thomason56bdd022012-02-09 18:16:58 -08001294 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001295 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
Lee Thomason43f59302012-02-06 18:18:11 -08001296 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001297
Lee Thomason6f381b72012-03-02 12:59:39 -08001298 p = attrib->ParseDeep( p, document->ProcessEntities() );
Lee Thomasond6277762012-02-22 16:00:12 -08001299 if ( !p || Attribute( attrib->Name() ) ) {
Lee Thomason43f59302012-02-06 18:18:11 -08001300 DELETE_ATTRIBUTE( attrib );
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001301 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001302 return 0;
1303 }
Lee Thomason5e3803c2012-04-16 08:57:05 -07001304 // There is a minor bug here: if the attribute in the source xml
1305 // document is duplicated, it will not be detected and the
1306 // attribute will be doubly added. However, tracking the 'prevAttribute'
1307 // avoids re-scanning the attribute list. Preferring performance for
1308 // now, may reconsider in the future.
1309 if ( prevAttribute ) {
1310 prevAttribute->next = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001311 }
1312 else {
1313 rootAttribute = attrib;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001314 }
Lee Thomason97088852012-04-18 11:39:42 -07001315 prevAttribute = attrib;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001316 }
Lee Thomasone4422302012-01-20 17:59:50 -08001317 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001318 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001319 closingType = CLOSED;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001320 return p+2; // done; sealed element.
1321 }
Lee Thomasone4422302012-01-20 17:59:50 -08001322 // end of the tag
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001323 else if ( *p == '>' ) {
1324 ++p;
1325 break;
1326 }
Lee Thomasone4422302012-01-20 17:59:50 -08001327 else {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001328 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasone4422302012-01-20 17:59:50 -08001329 return 0;
1330 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001331 }
Lee Thomason67d61312012-01-24 16:01:51 -08001332 return p;
1333}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001335
Lee Thomason67d61312012-01-24 16:01:51 -08001336//
1337// <ele></ele>
1338// <ele>foo<b>bar</b></ele>
1339//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001340char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001341{
1342 // Read the element name.
Lee Thomason56bdd022012-02-09 18:16:58 -08001343 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001344 if ( !p ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001345
1346 // The closing element is the </element> form. It is
1347 // parsed just like a regular element then deleted from
1348 // the DOM.
1349 if ( *p == '/' ) {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001350 closingType = CLOSING;
Lee Thomason67d61312012-01-24 16:01:51 -08001351 ++p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001352 }
Lee Thomason67d61312012-01-24 16:01:51 -08001353
Lee Thomason56bdd022012-02-09 18:16:58 -08001354 p = value.ParseName( p );
Lee Thomasond1983222012-02-06 08:41:24 -08001355 if ( value.Empty() ) return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001356
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001357 p = ParseAttributes( p );
1358 if ( !p || !*p || closingType )
Lee Thomason67d61312012-01-24 16:01:51 -08001359 return p;
1360
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001361 p = XMLNode::ParseDeep( p, strPair );
Lee Thomason67d61312012-01-24 16:01:51 -08001362 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001363}
1364
1365
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001366
1367XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1368{
1369 if ( !doc ) {
1370 doc = document;
1371 }
1372 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1373 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1374 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1375 }
1376 return element;
1377}
1378
1379
1380bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1381{
1382 const XMLElement* other = compare->ToElement();
1383 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1384
1385 const XMLAttribute* a=FirstAttribute();
1386 const XMLAttribute* b=other->FirstAttribute();
1387
1388 while ( a && b ) {
1389 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1390 return false;
1391 }
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001392 a = a->Next();
1393 b = b->Next();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001394 }
1395 if ( a || b ) {
1396 // different count
1397 return false;
1398 }
1399 return true;
1400 }
1401 return false;
1402}
1403
1404
Lee Thomason751da522012-02-10 08:50:51 -08001405bool XMLElement::Accept( XMLVisitor* visitor ) const
1406{
1407 if ( visitor->VisitEnter( *this, rootAttribute ) )
1408 {
1409 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1410 {
1411 if ( !node->Accept( visitor ) )
1412 break;
1413 }
1414 }
1415 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001416}
Lee Thomason56bdd022012-02-09 18:16:58 -08001417
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001418
Lee Thomason3f57d272012-01-11 15:30:03 -08001419// --------- XMLDocument ----------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001420XMLDocument::XMLDocument( bool _processEntities ) :
Lee Thomason18d68bd2012-01-26 18:17:26 -08001421 XMLNode( 0 ),
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001422 writeBOM( false ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001423 processEntities( _processEntities ),
1424 errorID( 0 ),
1425 errorStr1( 0 ),
1426 errorStr2( 0 ),
U-Lama\Lee560bd472011-12-28 19:42:49 -08001427 charBuffer( 0 )
1428{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001429 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001430}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001431
1432
Lee Thomason3f57d272012-01-11 15:30:03 -08001433XMLDocument::~XMLDocument()
1434{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001435 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001436 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001437
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001438#if 0
Lee Thomason455c9d42012-02-06 09:14:14 -08001439 textPool.Trace( "text" );
1440 elementPool.Trace( "element" );
1441 commentPool.Trace( "comment" );
1442 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001443#endif
1444
Lee Thomason455c9d42012-02-06 09:14:14 -08001445 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1446 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1447 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1448 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001449}
1450
1451
Lee Thomason18d68bd2012-01-26 18:17:26 -08001452void XMLDocument::InitDocument()
1453{
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001454 errorID = XML_NO_ERROR;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001455 errorStr1 = 0;
1456 errorStr2 = 0;
1457
1458 delete [] charBuffer;
1459 charBuffer = 0;
1460
1461}
1462
Lee Thomason3f57d272012-01-11 15:30:03 -08001463
Lee Thomason2c85a712012-01-31 08:24:24 -08001464XMLElement* XMLDocument::NewElement( const char* name )
1465{
Lee Thomasond1983222012-02-06 08:41:24 -08001466 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1467 ele->memPool = &elementPool;
Lee Thomason2c85a712012-01-31 08:24:24 -08001468 ele->SetName( name );
1469 return ele;
1470}
1471
1472
Lee Thomason1ff38e02012-02-14 18:18:16 -08001473XMLComment* XMLDocument::NewComment( const char* str )
1474{
1475 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1476 comment->memPool = &commentPool;
1477 comment->SetValue( str );
1478 return comment;
1479}
1480
1481
1482XMLText* XMLDocument::NewText( const char* str )
1483{
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001484 XMLText* text = new (textPool.Alloc()) XMLText( this );
1485 text->memPool = &textPool;
1486 text->SetValue( str );
1487 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001488}
1489
1490
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001491XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1492{
1493 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1494 dec->memPool = &commentPool;
Lee Thomasonf68c4382012-04-28 14:37:11 -07001495 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001496 return dec;
1497}
1498
1499
1500XMLUnknown* XMLDocument::NewUnknown( const char* str )
1501{
1502 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1503 unk->memPool = &commentPool;
1504 unk->SetValue( str );
1505 return unk;
1506}
1507
1508
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001509int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001510{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001511 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001512 InitDocument();
1513
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001514#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001515#pragma warning ( push )
1516#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001517#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001518 FILE* fp = fopen( filename, "rb" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001519#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001520#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001521#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001522 if ( !fp ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001523 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001524 return errorID;
1525 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001526 LoadFile( fp );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001527 fclose( fp );
1528 return errorID;
1529}
1530
1531
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001532int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001533{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001534 DeleteChildren();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001535 InitDocument();
1536
1537 fseek( fp, 0, SEEK_END );
1538 unsigned size = ftell( fp );
1539 fseek( fp, 0, SEEK_SET );
1540
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001541 if ( size == 0 ) {
1542 return errorID;
1543 }
1544
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001545 charBuffer = new char[size+1];
Lee Thomasona3efec02012-06-15 14:30:44 -07001546 size_t read = fread( charBuffer, 1, size, fp );
1547 if ( read != size ) {
1548 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1549 return errorID;
1550 }
1551
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001552 charBuffer[size] = 0;
1553
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001554 const char* p = charBuffer;
1555 p = XMLUtil::SkipWhiteSpace( p );
1556 p = XMLUtil::ReadBOM( p, &writeBOM );
1557 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001558 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001559 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001560 }
1561
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001562 ParseDeep( charBuffer + (p-charBuffer), 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001563 return errorID;
1564}
1565
1566
Ken Miller81da1fb2012-04-09 23:32:26 -05001567int XMLDocument::SaveFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001568{
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001570#pragma warning ( push )
1571#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572#endif
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001573 FILE* fp = fopen( filename, "w" );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001574#if defined(_MSC_VER)
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001575#pragma warning ( pop )
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001576#endif
Ken Miller81da1fb2012-04-09 23:32:26 -05001577 if ( !fp ) {
Lee Thomason7f7b1622012-03-24 12:49:03 -07001578 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Ken Miller81da1fb2012-04-09 23:32:26 -05001579 return errorID;
Lee Thomason7f7b1622012-03-24 12:49:03 -07001580 }
Ken Miller81da1fb2012-04-09 23:32:26 -05001581 SaveFile(fp);
1582 fclose( fp );
1583 return errorID;
1584}
1585
1586
1587int XMLDocument::SaveFile( FILE* fp )
1588{
1589 XMLPrinter stream( fp );
1590 Print( &stream );
1591 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001592}
1593
Lee Thomason1ff38e02012-02-14 18:18:16 -08001594
Lee Thomason7c913cd2012-01-26 18:32:34 -08001595int XMLDocument::Parse( const char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -08001596{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001597 DeleteChildren();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001598 InitDocument();
1599
1600 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001601 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001602 return errorID;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001603 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001604 p = XMLUtil::SkipWhiteSpace( p );
1605 p = XMLUtil::ReadBOM( p, &writeBOM );
1606 if ( !p || !*p ) {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001607 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomasond6277762012-02-22 16:00:12 -08001608 return errorID;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001609 }
1610
Lee Thomason18d68bd2012-01-26 18:17:26 -08001611 size_t len = strlen( p );
1612 charBuffer = new char[ len+1 ];
1613 memcpy( charBuffer, p, len+1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001614
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001615
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001616 ParseDeep( charBuffer, 0 );
Lee Thomason7c913cd2012-01-26 18:32:34 -08001617 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001618}
1619
1620
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001621void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001622{
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001623 XMLPrinter stdStreamer( stdout );
Lee Thomason5cae8972012-01-24 18:03:07 -08001624 if ( !streamer )
1625 streamer = &stdStreamer;
Lee Thomason751da522012-02-10 08:50:51 -08001626 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001627}
1628
1629
Lee Thomason67d61312012-01-24 16:01:51 -08001630void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1631{
Lee Thomason18d68bd2012-01-26 18:17:26 -08001632 errorID = error;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001633 errorStr1 = str1;
1634 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001635}
1636
Lee Thomason5cae8972012-01-24 18:03:07 -08001637
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001638void XMLDocument::PrintError() const
1639{
1640 if ( errorID ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001641 static const int LEN = 20;
1642 char buf1[LEN] = { 0 };
1643 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001644
1645 if ( errorStr1 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001646 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001647 }
1648 if ( errorStr2 ) {
Lee Thomason (grinliz)5ce4d972012-02-26 21:14:23 -08001649 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001650 }
1651
1652 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1653 errorID, buf1, buf2 );
1654 }
1655}
1656
1657
sniperbat25900882012-05-28 17:22:07 +08001658XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001659 elementJustOpened( false ),
1660 firstElement( true ),
1661 fp( file ),
1662 depth( 0 ),
Lee Thomason6f381b72012-03-02 12:59:39 -08001663 textDepth( -1 ),
sniperbat25900882012-05-28 17:22:07 +08001664 processEntities( true ),
1665 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001666{
Lee Thomason857b8682012-01-25 17:50:25 -08001667 for( int i=0; i<ENTITY_RANGE; ++i ) {
1668 entityFlag[i] = false;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001669 restrictedEntityFlag[i] = false;
Lee Thomason857b8682012-01-25 17:50:25 -08001670 }
1671 for( int i=0; i<NUM_ENTITIES; ++i ) {
1672 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1673 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001674 entityFlag[ (int)entities[i].value ] = true;
Lee Thomason857b8682012-01-25 17:50:25 -08001675 }
1676 }
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001677 restrictedEntityFlag[(int)'&'] = true;
1678 restrictedEntityFlag[(int)'<'] = true;
1679 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
U-Stream\Leeae25a442012-02-17 17:48:16 -08001680 buffer.Push( 0 );
1681}
1682
1683
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001684void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001685{
1686 va_list va;
1687 va_start( va, format );
1688
1689 if ( fp ) {
1690 vfprintf( fp, format, va );
1691 }
1692 else {
1693 // This seems brutally complex. Haven't figured out a better
1694 // way on windows.
1695 #ifdef _MSC_VER
1696 int len = -1;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001697 int expand = 1000;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001698 while ( len < 0 ) {
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001699 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001700 if ( len < 0 ) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001701 expand *= 3/2;
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -07001702 accumulator.PushArr( expand );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001703 }
1704 }
1705 char* p = buffer.PushArr( len ) - 1;
1706 memcpy( p, accumulator.Mem(), len+1 );
1707 #else
1708 int len = vsnprintf( 0, 0, format, va );
Lee Thomason4de93472012-03-13 17:33:35 -07001709 // Close out and re-start the va-args
1710 va_end( va );
1711 va_start( va, format );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001712 char* p = buffer.PushArr( len ) - 1;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001713 vsnprintf( p, len+1, format, va );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001714 #endif
1715 }
1716 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001717}
1718
1719
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001720void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001721{
1722 for( int i=0; i<depth; ++i ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001723 Print( " " );
Lee Thomason5cae8972012-01-24 18:03:07 -08001724 }
1725}
1726
1727
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001728void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001729{
Lee Thomason951d8832012-01-26 08:47:06 -08001730 // Look for runs of bytes between entities to print.
1731 const char* q = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001732 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001733
Lee Thomason6f381b72012-03-02 12:59:39 -08001734 if ( processEntities ) {
1735 while ( *q ) {
1736 // Remember, char is sometimes signed. (How many times has that bitten me?)
1737 if ( *q > 0 && *q < ENTITY_RANGE ) {
1738 // Check for entities. If one is found, flush
1739 // the stream up until the entity, write the
1740 // entity, and keep looking.
Lee Thomason (grinliz)8a0975d2012-03-31 20:09:20 -07001741 if ( flag[(unsigned)(*q)] ) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001742 while ( p < q ) {
1743 Print( "%c", *p );
1744 ++p;
1745 }
1746 for( int i=0; i<NUM_ENTITIES; ++i ) {
1747 if ( entities[i].value == *q ) {
1748 Print( "&%s;", entities[i].pattern );
1749 break;
1750 }
1751 }
Lee Thomason951d8832012-01-26 08:47:06 -08001752 ++p;
1753 }
Lee Thomason951d8832012-01-26 08:47:06 -08001754 }
Lee Thomason6f381b72012-03-02 12:59:39 -08001755 ++q;
Lee Thomason951d8832012-01-26 08:47:06 -08001756 }
Lee Thomason951d8832012-01-26 08:47:06 -08001757 }
1758 // Flush the remaining string. This will be the entire
1759 // string if an entity wasn't found.
Lee Thomason6f381b72012-03-02 12:59:39 -08001760 if ( !processEntities || (q-p > 0) ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001761 Print( "%s", p );
Lee Thomason951d8832012-01-26 08:47:06 -08001762 }
Lee Thomason857b8682012-01-25 17:50:25 -08001763}
1764
U-Stream\Leeae25a442012-02-17 17:48:16 -08001765
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001766void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001767{
1768 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1769 if ( writeBOM ) {
1770 Print( "%s", bom );
1771 }
1772 if ( writeDec ) {
1773 PushDeclaration( "xml version=\"1.0\"" );
1774 }
1775}
1776
1777
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001778void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001779{
1780 if ( elementJustOpened ) {
1781 SealElement();
1782 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001783 stack.Push( name );
1784
sniperbat25900882012-05-28 17:22:07 +08001785 if ( textDepth < 0 && !firstElement && !compactMode ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001786 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001787 PrintSpace( depth );
1788 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001789
U-Stream\Leeae25a442012-02-17 17:48:16 -08001790 Print( "<%s", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001791 elementJustOpened = true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001792 firstElement = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001793 ++depth;
1794}
1795
1796
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001797void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001798{
1799 TIXMLASSERT( elementJustOpened );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001800 Print( " %s=\"", name );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001801 PrintString( value, false );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001802 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001803}
1804
1805
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001806void XMLPrinter::PushAttribute( const char* name, int v )
1807{
1808 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001809 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001810 PushAttribute( name, buf );
1811}
1812
1813
1814void XMLPrinter::PushAttribute( const char* name, unsigned v )
1815{
1816 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001817 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001818 PushAttribute( name, buf );
1819}
1820
1821
1822void XMLPrinter::PushAttribute( const char* name, bool v )
1823{
1824 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001825 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001826 PushAttribute( name, buf );
1827}
1828
1829
1830void XMLPrinter::PushAttribute( const char* name, double v )
1831{
1832 char buf[BUF_SIZE];
Lee Thomason21be8822012-07-15 17:27:22 -07001833 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001834 PushAttribute( name, buf );
1835}
1836
1837
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001838void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001839{
1840 --depth;
1841 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001842
1843 if ( elementJustOpened ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001844 Print( "/>" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001845 }
1846 else {
sniperbat25900882012-05-28 17:22:07 +08001847 if ( textDepth < 0 && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001848 Print( "\n" );
Lee Thomason24767b02012-01-25 17:16:23 -08001849 PrintSpace( depth );
1850 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001851 Print( "</%s>", name );
Lee Thomason5cae8972012-01-24 18:03:07 -08001852 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001853
1854 if ( textDepth == depth )
1855 textDepth = -1;
sniperbat25900882012-05-28 17:22:07 +08001856 if ( depth == 0 && !compactMode)
U-Stream\Leeae25a442012-02-17 17:48:16 -08001857 Print( "\n" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001858 elementJustOpened = false;
1859}
1860
1861
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001862void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001863{
1864 elementJustOpened = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001865 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001866}
1867
1868
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001869void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001870{
Lee Thomason56bdd022012-02-09 18:16:58 -08001871 textDepth = depth-1;
1872
Lee Thomason5cae8972012-01-24 18:03:07 -08001873 if ( elementJustOpened ) {
1874 SealElement();
1875 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001876 if ( cdata ) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001877 Print( "<![CDATA[" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001878 Print( "%s", text );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001879 Print( "]]>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001880 }
1881 else {
1882 PrintString( text, true );
1883 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001884}
1885
Lee Thomason21be8822012-07-15 17:27:22 -07001886void XMLPrinter::PushText( int value )
1887{
1888 char buf[BUF_SIZE];
1889 XMLUtil::ToStr( value, buf, BUF_SIZE );
1890 PushText( buf, false );
1891}
1892
1893
1894void XMLPrinter::PushText( unsigned value )
1895{
1896 char buf[BUF_SIZE];
1897 XMLUtil::ToStr( value, buf, BUF_SIZE );
1898 PushText( buf, false );
1899}
1900
1901
1902void XMLPrinter::PushText( bool value )
1903{
1904 char buf[BUF_SIZE];
1905 XMLUtil::ToStr( value, buf, BUF_SIZE );
1906 PushText( buf, false );
1907}
1908
1909
1910void XMLPrinter::PushText( float value )
1911{
1912 char buf[BUF_SIZE];
1913 XMLUtil::ToStr( value, buf, BUF_SIZE );
1914 PushText( buf, false );
1915}
1916
1917
1918void XMLPrinter::PushText( double value )
1919{
1920 char buf[BUF_SIZE];
1921 XMLUtil::ToStr( value, buf, BUF_SIZE );
1922 PushText( buf, false );
1923}
1924
Lee Thomason5cae8972012-01-24 18:03:07 -08001925
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001926void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001927{
1928 if ( elementJustOpened ) {
1929 SealElement();
1930 }
sniperbat25900882012-05-28 17:22:07 +08001931 if ( textDepth < 0 && !firstElement && !compactMode) {
U-Stream\Leeae25a442012-02-17 17:48:16 -08001932 Print( "\n" );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001933 PrintSpace( depth );
1934 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001935 firstElement = false;
U-Stream\Leeae25a442012-02-17 17:48:16 -08001936 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08001937}
Lee Thomason751da522012-02-10 08:50:51 -08001938
1939
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001940void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001941{
1942 if ( elementJustOpened ) {
1943 SealElement();
1944 }
sniperbat25900882012-05-28 17:22:07 +08001945 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001946 Print( "\n" );
1947 PrintSpace( depth );
1948 }
1949 firstElement = false;
1950 Print( "<?%s?>", value );
1951}
1952
1953
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001954void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001955{
1956 if ( elementJustOpened ) {
1957 SealElement();
1958 }
sniperbat25900882012-05-28 17:22:07 +08001959 if ( textDepth < 0 && !firstElement && !compactMode) {
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001960 Print( "\n" );
1961 PrintSpace( depth );
1962 }
1963 firstElement = false;
1964 Print( "<!%s>", value );
1965}
1966
1967
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001968bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001969{
Lee Thomason6f381b72012-03-02 12:59:39 -08001970 processEntities = doc.ProcessEntities();
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001971 if ( doc.HasBOM() ) {
1972 PushHeader( true, false );
1973 }
1974 return true;
1975}
1976
1977
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001978bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08001979{
1980 OpenElement( element.Name() );
1981 while ( attribute ) {
1982 PushAttribute( attribute->Name(), attribute->Value() );
1983 attribute = attribute->Next();
1984 }
1985 return true;
1986}
1987
1988
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001989bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08001990{
1991 CloseElement();
1992 return true;
1993}
1994
1995
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001996bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08001997{
Lee Thomasond6277762012-02-22 16:00:12 -08001998 PushText( text.Value(), text.CData() );
Lee Thomason751da522012-02-10 08:50:51 -08001999 return true;
2000}
2001
2002
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002003bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002004{
2005 PushComment( comment.Value() );
2006 return true;
2007}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002008
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002009bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002010{
2011 PushDeclaration( declaration.Value() );
2012 return true;
2013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002017{
2018 PushUnknown( unknown.Value() );
2019 return true;
2020}