stratgame

annotate level/src/tinyxml2.cc @ 3:8d95187cb3ee

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 23 May 2012 17:10:46 +0300
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 Original code by Lee Thomason (www.grinninglizard.com)
nuclear@0 3
nuclear@0 4 This software is provided 'as-is', without any express or implied
nuclear@0 5 warranty. In no event will the authors be held liable for any
nuclear@0 6 damages arising from the use of this software.
nuclear@0 7
nuclear@0 8 Permission is granted to anyone to use this software for any
nuclear@0 9 purpose, including commercial applications, and to alter it and
nuclear@0 10 redistribute it freely, subject to the following restrictions:
nuclear@0 11
nuclear@0 12 1. The origin of this software must not be misrepresented; you must
nuclear@0 13 not claim that you wrote the original software. If you use this
nuclear@0 14 software in a product, an acknowledgment in the product documentation
nuclear@0 15 would be appreciated but is not required.
nuclear@0 16
nuclear@0 17 2. Altered source versions must be plainly marked as such, and
nuclear@0 18 must not be misrepresented as being the original software.
nuclear@0 19
nuclear@0 20 3. This notice may not be removed or altered from any source
nuclear@0 21 distribution.
nuclear@0 22 */
nuclear@0 23
nuclear@0 24 #include "tinyxml2.h"
nuclear@0 25
nuclear@0 26 #include <cstdio>
nuclear@0 27 #include <cstdlib>
nuclear@0 28 #include <new>
nuclear@0 29 #include <cstddef>
nuclear@0 30
nuclear@0 31 using namespace tinyxml2;
nuclear@0 32
nuclear@0 33 static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
nuclear@0 34 static const char LF = LINE_FEED;
nuclear@0 35 static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
nuclear@0 36 static const char CR = CARRIAGE_RETURN;
nuclear@0 37 static const char SINGLE_QUOTE = '\'';
nuclear@0 38 static const char DOUBLE_QUOTE = '\"';
nuclear@0 39
nuclear@0 40 // Bunch of unicode info at:
nuclear@0 41 // http://www.unicode.org/faq/utf_bom.html
nuclear@0 42 // ef bb bf (Microsoft "lead bytes") - designates UTF-8
nuclear@0 43
nuclear@0 44 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
nuclear@0 45 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
nuclear@0 46 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
nuclear@0 47
nuclear@0 48
nuclear@0 49 #define DELETE_NODE( node ) { \
nuclear@0 50 if ( node ) { \
nuclear@0 51 MemPool* pool = node->memPool; \
nuclear@0 52 node->~XMLNode(); \
nuclear@0 53 pool->Free( node ); \
nuclear@0 54 } \
nuclear@0 55 }
nuclear@0 56 #define DELETE_ATTRIBUTE( attrib ) { \
nuclear@0 57 if ( attrib ) { \
nuclear@0 58 MemPool* pool = attrib->memPool; \
nuclear@0 59 attrib->~XMLAttribute(); \
nuclear@0 60 pool->Free( attrib ); \
nuclear@0 61 } \
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 struct Entity {
nuclear@0 65 const char* pattern;
nuclear@0 66 int length;
nuclear@0 67 char value;
nuclear@0 68 };
nuclear@0 69
nuclear@0 70 static const int NUM_ENTITIES = 5;
nuclear@0 71 static const Entity entities[NUM_ENTITIES] =
nuclear@0 72 {
nuclear@0 73 { "quot", 4, DOUBLE_QUOTE },
nuclear@0 74 { "amp", 3, '&' },
nuclear@0 75 { "apos", 4, SINGLE_QUOTE },
nuclear@0 76 { "lt", 2, '<' },
nuclear@0 77 { "gt", 2, '>' }
nuclear@0 78 };
nuclear@0 79
nuclear@0 80
nuclear@0 81 StrPair::~StrPair()
nuclear@0 82 {
nuclear@0 83 Reset();
nuclear@0 84 }
nuclear@0 85
nuclear@0 86
nuclear@0 87 void StrPair::Reset()
nuclear@0 88 {
nuclear@0 89 if ( flags & NEEDS_DELETE ) {
nuclear@0 90 delete [] start;
nuclear@0 91 }
nuclear@0 92 flags = 0;
nuclear@0 93 start = 0;
nuclear@0 94 end = 0;
nuclear@0 95 }
nuclear@0 96
nuclear@0 97
nuclear@0 98 void StrPair::SetStr( const char* str, int flags )
nuclear@0 99 {
nuclear@0 100 Reset();
nuclear@0 101 size_t len = strlen( str );
nuclear@0 102 start = new char[ len+1 ];
nuclear@0 103 memcpy( start, str, len+1 );
nuclear@0 104 end = start + len;
nuclear@0 105 this->flags = flags | NEEDS_DELETE;
nuclear@0 106 }
nuclear@0 107
nuclear@0 108
nuclear@0 109 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
nuclear@0 110 {
nuclear@0 111 TIXMLASSERT( endTag && *endTag );
nuclear@0 112
nuclear@0 113 char* start = p; // fixme: hides a member
nuclear@0 114 char endChar = *endTag;
nuclear@0 115 size_t length = strlen( endTag );
nuclear@0 116
nuclear@0 117 // Inner loop of text parsing.
nuclear@0 118 while ( *p ) {
nuclear@0 119 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
nuclear@0 120 Set( start, p, strFlags );
nuclear@0 121 return p + length;
nuclear@0 122 }
nuclear@0 123 ++p;
nuclear@0 124 }
nuclear@0 125 return 0;
nuclear@0 126 }
nuclear@0 127
nuclear@0 128
nuclear@0 129 char* StrPair::ParseName( char* p )
nuclear@0 130 {
nuclear@0 131 char* start = p;
nuclear@0 132
nuclear@0 133 if ( !start || !(*start) ) {
nuclear@0 134 return 0;
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 if ( !XMLUtil::IsAlpha( *p ) ) {
nuclear@0 138 return 0;
nuclear@0 139 }
nuclear@0 140
nuclear@0 141 while( *p && (
nuclear@0 142 XMLUtil::IsAlphaNum( (unsigned char) *p )
nuclear@0 143 || *p == '_'
nuclear@0 144 || *p == '-'
nuclear@0 145 || *p == '.'
nuclear@0 146 || *p == ':' ))
nuclear@0 147 {
nuclear@0 148 ++p;
nuclear@0 149 }
nuclear@0 150
nuclear@0 151 if ( p > start ) {
nuclear@0 152 Set( start, p, 0 );
nuclear@0 153 return p;
nuclear@0 154 }
nuclear@0 155 return 0;
nuclear@0 156 }
nuclear@0 157
nuclear@0 158
nuclear@0 159
nuclear@0 160 const char* StrPair::GetStr()
nuclear@0 161 {
nuclear@0 162 if ( flags & NEEDS_FLUSH ) {
nuclear@0 163 *end = 0;
nuclear@0 164 flags ^= NEEDS_FLUSH;
nuclear@0 165
nuclear@0 166 if ( flags ) {
nuclear@0 167 char* p = start; // the read pointer
nuclear@0 168 char* q = start; // the write pointer
nuclear@0 169
nuclear@0 170 while( p < end ) {
nuclear@0 171 if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
nuclear@0 172 // CR-LF pair becomes LF
nuclear@0 173 // CR alone becomes LF
nuclear@0 174 // LF-CR becomes LF
nuclear@0 175 if ( *(p+1) == LF ) {
nuclear@0 176 p += 2;
nuclear@0 177 }
nuclear@0 178 else {
nuclear@0 179 ++p;
nuclear@0 180 }
nuclear@0 181 *q++ = LF;
nuclear@0 182 }
nuclear@0 183 else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
nuclear@0 184 if ( *(p+1) == CR ) {
nuclear@0 185 p += 2;
nuclear@0 186 }
nuclear@0 187 else {
nuclear@0 188 ++p;
nuclear@0 189 }
nuclear@0 190 *q++ = LF;
nuclear@0 191 }
nuclear@0 192 else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
nuclear@0 193 int i=0;
nuclear@0 194
nuclear@0 195 // Entities handled by tinyXML2:
nuclear@0 196 // - special entities in the entity table [in/out]
nuclear@0 197 // - numeric character reference [in]
nuclear@0 198 // &#20013; or &#x4e2d;
nuclear@0 199
nuclear@0 200 if ( *(p+1) == '#' ) {
nuclear@0 201 char buf[10] = { 0 };
nuclear@0 202 int len;
nuclear@0 203 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
nuclear@0 204 for( int i=0; i<len; ++i ) {
nuclear@0 205 *q++ = buf[i];
nuclear@0 206 }
nuclear@0 207 TIXMLASSERT( q <= p );
nuclear@0 208 }
nuclear@0 209 else {
nuclear@0 210 for( i=0; i<NUM_ENTITIES; ++i ) {
nuclear@0 211 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
nuclear@0 212 && *(p+entities[i].length+1) == ';' )
nuclear@0 213 {
nuclear@0 214 // Found an entity convert;
nuclear@0 215 *q = entities[i].value;
nuclear@0 216 ++q;
nuclear@0 217 p += entities[i].length + 2;
nuclear@0 218 break;
nuclear@0 219 }
nuclear@0 220 }
nuclear@0 221 if ( i == NUM_ENTITIES ) {
nuclear@0 222 // fixme: treat as error?
nuclear@0 223 ++p;
nuclear@0 224 ++q;
nuclear@0 225 }
nuclear@0 226 }
nuclear@0 227 }
nuclear@0 228 else {
nuclear@0 229 *q = *p;
nuclear@0 230 ++p;
nuclear@0 231 ++q;
nuclear@0 232 }
nuclear@0 233 }
nuclear@0 234 *q = 0;
nuclear@0 235 }
nuclear@0 236 flags = (flags & NEEDS_DELETE);
nuclear@0 237 }
nuclear@0 238 return start;
nuclear@0 239 }
nuclear@0 240
nuclear@0 241
nuclear@0 242
nuclear@0 243
nuclear@0 244 // --------- XMLUtil ----------- //
nuclear@0 245
nuclear@0 246 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
nuclear@0 247 {
nuclear@0 248 *bom = false;
nuclear@0 249 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
nuclear@0 250 // Check for BOM:
nuclear@0 251 if ( *(pu+0) == TIXML_UTF_LEAD_0
nuclear@0 252 && *(pu+1) == TIXML_UTF_LEAD_1
nuclear@0 253 && *(pu+2) == TIXML_UTF_LEAD_2 )
nuclear@0 254 {
nuclear@0 255 *bom = true;
nuclear@0 256 p += 3;
nuclear@0 257 }
nuclear@0 258 return p;
nuclear@0 259 }
nuclear@0 260
nuclear@0 261
nuclear@0 262 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
nuclear@0 263 {
nuclear@0 264 const unsigned long BYTE_MASK = 0xBF;
nuclear@0 265 const unsigned long BYTE_MARK = 0x80;
nuclear@0 266 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
nuclear@0 267
nuclear@0 268 if (input < 0x80)
nuclear@0 269 *length = 1;
nuclear@0 270 else if ( input < 0x800 )
nuclear@0 271 *length = 2;
nuclear@0 272 else if ( input < 0x10000 )
nuclear@0 273 *length = 3;
nuclear@0 274 else if ( input < 0x200000 )
nuclear@0 275 *length = 4;
nuclear@0 276 else
nuclear@0 277 { *length = 0; return; } // This code won't covert this correctly anyway.
nuclear@0 278
nuclear@0 279 output += *length;
nuclear@0 280
nuclear@0 281 // Scary scary fall throughs.
nuclear@0 282 switch (*length)
nuclear@0 283 {
nuclear@0 284 case 4:
nuclear@0 285 --output;
nuclear@0 286 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
nuclear@0 287 input >>= 6;
nuclear@0 288 case 3:
nuclear@0 289 --output;
nuclear@0 290 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
nuclear@0 291 input >>= 6;
nuclear@0 292 case 2:
nuclear@0 293 --output;
nuclear@0 294 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
nuclear@0 295 input >>= 6;
nuclear@0 296 case 1:
nuclear@0 297 --output;
nuclear@0 298 *output = (char)(input | FIRST_BYTE_MARK[*length]);
nuclear@0 299 }
nuclear@0 300 }
nuclear@0 301
nuclear@0 302
nuclear@0 303 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
nuclear@0 304 {
nuclear@0 305 // Presume an entity, and pull it out.
nuclear@0 306 *length = 0;
nuclear@0 307
nuclear@0 308 if ( *(p+1) == '#' && *(p+2) )
nuclear@0 309 {
nuclear@0 310 unsigned long ucs = 0;
nuclear@0 311 ptrdiff_t delta = 0;
nuclear@0 312 unsigned mult = 1;
nuclear@0 313
nuclear@0 314 if ( *(p+2) == 'x' )
nuclear@0 315 {
nuclear@0 316 // Hexadecimal.
nuclear@0 317 if ( !*(p+3) ) return 0;
nuclear@0 318
nuclear@0 319 const char* q = p+3;
nuclear@0 320 q = strchr( q, ';' );
nuclear@0 321
nuclear@0 322 if ( !q || !*q ) return 0;
nuclear@0 323
nuclear@0 324 delta = q-p;
nuclear@0 325 --q;
nuclear@0 326
nuclear@0 327 while ( *q != 'x' )
nuclear@0 328 {
nuclear@0 329 if ( *q >= '0' && *q <= '9' )
nuclear@0 330 ucs += mult * (*q - '0');
nuclear@0 331 else if ( *q >= 'a' && *q <= 'f' )
nuclear@0 332 ucs += mult * (*q - 'a' + 10);
nuclear@0 333 else if ( *q >= 'A' && *q <= 'F' )
nuclear@0 334 ucs += mult * (*q - 'A' + 10 );
nuclear@0 335 else
nuclear@0 336 return 0;
nuclear@0 337 mult *= 16;
nuclear@0 338 --q;
nuclear@0 339 }
nuclear@0 340 }
nuclear@0 341 else
nuclear@0 342 {
nuclear@0 343 // Decimal.
nuclear@0 344 if ( !*(p+2) ) return 0;
nuclear@0 345
nuclear@0 346 const char* q = p+2;
nuclear@0 347 q = strchr( q, ';' );
nuclear@0 348
nuclear@0 349 if ( !q || !*q ) return 0;
nuclear@0 350
nuclear@0 351 delta = q-p;
nuclear@0 352 --q;
nuclear@0 353
nuclear@0 354 while ( *q != '#' )
nuclear@0 355 {
nuclear@0 356 if ( *q >= '0' && *q <= '9' )
nuclear@0 357 ucs += mult * (*q - '0');
nuclear@0 358 else
nuclear@0 359 return 0;
nuclear@0 360 mult *= 10;
nuclear@0 361 --q;
nuclear@0 362 }
nuclear@0 363 }
nuclear@0 364 // convert the UCS to UTF-8
nuclear@0 365 ConvertUTF32ToUTF8( ucs, value, length );
nuclear@0 366 return p + delta + 1;
nuclear@0 367 }
nuclear@0 368 return p+1;
nuclear@0 369 }
nuclear@0 370
nuclear@0 371
nuclear@0 372 char* XMLDocument::Identify( char* p, XMLNode** node )
nuclear@0 373 {
nuclear@0 374 XMLNode* returnNode = 0;
nuclear@0 375 char* start = p;
nuclear@0 376 p = XMLUtil::SkipWhiteSpace( p );
nuclear@0 377 if( !p || !*p )
nuclear@0 378 {
nuclear@0 379 return p;
nuclear@0 380 }
nuclear@0 381
nuclear@0 382 // What is this thing?
nuclear@0 383 // - Elements start with a letter or underscore, but xml is reserved.
nuclear@0 384 // - Comments: <!--
nuclear@0 385 // - Decleration: <?
nuclear@0 386 // - Everthing else is unknown to tinyxml.
nuclear@0 387 //
nuclear@0 388
nuclear@0 389 static const char* xmlHeader = { "<?" };
nuclear@0 390 static const char* commentHeader = { "<!--" };
nuclear@0 391 static const char* dtdHeader = { "<!" };
nuclear@0 392 static const char* cdataHeader = { "<![CDATA[" };
nuclear@0 393 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
nuclear@0 394
nuclear@0 395 static const int xmlHeaderLen = 2;
nuclear@0 396 static const int commentHeaderLen = 4;
nuclear@0 397 static const int dtdHeaderLen = 2;
nuclear@0 398 static const int cdataHeaderLen = 9;
nuclear@0 399 static const int elementHeaderLen = 1;
nuclear@0 400
nuclear@0 401 #if defined(_MSC_VER)
nuclear@0 402 #pragma warning ( push )
nuclear@0 403 #pragma warning ( disable : 4127 )
nuclear@0 404 #endif
nuclear@0 405 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
nuclear@0 406 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
nuclear@0 407 #if defined(_MSC_VER)
nuclear@0 408 #pragma warning (pop)
nuclear@0 409 #endif
nuclear@0 410 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
nuclear@0 411 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
nuclear@0 412 returnNode->memPool = &commentPool;
nuclear@0 413 p += xmlHeaderLen;
nuclear@0 414 }
nuclear@0 415 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
nuclear@0 416 returnNode = new (commentPool.Alloc()) XMLComment( this );
nuclear@0 417 returnNode->memPool = &commentPool;
nuclear@0 418 p += commentHeaderLen;
nuclear@0 419 }
nuclear@0 420 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
nuclear@0 421 XMLText* text = new (textPool.Alloc()) XMLText( this );
nuclear@0 422 returnNode = text;
nuclear@0 423 returnNode->memPool = &textPool;
nuclear@0 424 p += cdataHeaderLen;
nuclear@0 425 text->SetCData( true );
nuclear@0 426 }
nuclear@0 427 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
nuclear@0 428 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
nuclear@0 429 returnNode->memPool = &commentPool;
nuclear@0 430 p += dtdHeaderLen;
nuclear@0 431 }
nuclear@0 432 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
nuclear@0 433 returnNode = new (elementPool.Alloc()) XMLElement( this );
nuclear@0 434 returnNode->memPool = &elementPool;
nuclear@0 435 p += elementHeaderLen;
nuclear@0 436 }
nuclear@0 437 else {
nuclear@0 438 returnNode = new (textPool.Alloc()) XMLText( this );
nuclear@0 439 returnNode->memPool = &textPool;
nuclear@0 440 p = start; // Back it up, all the text counts.
nuclear@0 441 }
nuclear@0 442
nuclear@0 443 *node = returnNode;
nuclear@0 444 return p;
nuclear@0 445 }
nuclear@0 446
nuclear@0 447
nuclear@0 448 bool XMLDocument::Accept( XMLVisitor* visitor ) const
nuclear@0 449 {
nuclear@0 450 if ( visitor->VisitEnter( *this ) )
nuclear@0 451 {
nuclear@0 452 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
nuclear@0 453 {
nuclear@0 454 if ( !node->Accept( visitor ) )
nuclear@0 455 break;
nuclear@0 456 }
nuclear@0 457 }
nuclear@0 458 return visitor->VisitExit( *this );
nuclear@0 459 }
nuclear@0 460
nuclear@0 461
nuclear@0 462 // --------- XMLNode ----------- //
nuclear@0 463
nuclear@0 464 XMLNode::XMLNode( XMLDocument* doc ) :
nuclear@0 465 document( doc ),
nuclear@0 466 parent( 0 ),
nuclear@0 467 firstChild( 0 ), lastChild( 0 ),
nuclear@0 468 prev( 0 ), next( 0 )
nuclear@0 469 {
nuclear@0 470 }
nuclear@0 471
nuclear@0 472
nuclear@0 473 XMLNode::~XMLNode()
nuclear@0 474 {
nuclear@0 475 DeleteChildren();
nuclear@0 476 if ( parent ) {
nuclear@0 477 parent->Unlink( this );
nuclear@0 478 }
nuclear@0 479 }
nuclear@0 480
nuclear@0 481
nuclear@0 482 void XMLNode::SetValue( const char* str, bool staticMem )
nuclear@0 483 {
nuclear@0 484 if ( staticMem )
nuclear@0 485 value.SetInternedStr( str );
nuclear@0 486 else
nuclear@0 487 value.SetStr( str );
nuclear@0 488 }
nuclear@0 489
nuclear@0 490
nuclear@0 491 void XMLNode::DeleteChildren()
nuclear@0 492 {
nuclear@0 493 while( firstChild ) {
nuclear@0 494 XMLNode* node = firstChild;
nuclear@0 495 Unlink( node );
nuclear@0 496
nuclear@0 497 DELETE_NODE( node );
nuclear@0 498 }
nuclear@0 499 firstChild = lastChild = 0;
nuclear@0 500 }
nuclear@0 501
nuclear@0 502
nuclear@0 503 void XMLNode::Unlink( XMLNode* child )
nuclear@0 504 {
nuclear@0 505 TIXMLASSERT( child->parent == this );
nuclear@0 506 if ( child == firstChild )
nuclear@0 507 firstChild = firstChild->next;
nuclear@0 508 if ( child == lastChild )
nuclear@0 509 lastChild = lastChild->prev;
nuclear@0 510
nuclear@0 511 if ( child->prev ) {
nuclear@0 512 child->prev->next = child->next;
nuclear@0 513 }
nuclear@0 514 if ( child->next ) {
nuclear@0 515 child->next->prev = child->prev;
nuclear@0 516 }
nuclear@0 517 child->parent = 0;
nuclear@0 518 }
nuclear@0 519
nuclear@0 520
nuclear@0 521 void XMLNode::DeleteChild( XMLNode* node )
nuclear@0 522 {
nuclear@0 523 TIXMLASSERT( node->parent == this );
nuclear@0 524 DELETE_NODE( node );
nuclear@0 525 }
nuclear@0 526
nuclear@0 527
nuclear@0 528 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
nuclear@0 529 {
nuclear@0 530 if ( lastChild ) {
nuclear@0 531 TIXMLASSERT( firstChild );
nuclear@0 532 TIXMLASSERT( lastChild->next == 0 );
nuclear@0 533 lastChild->next = addThis;
nuclear@0 534 addThis->prev = lastChild;
nuclear@0 535 lastChild = addThis;
nuclear@0 536
nuclear@0 537 addThis->next = 0;
nuclear@0 538 }
nuclear@0 539 else {
nuclear@0 540 TIXMLASSERT( firstChild == 0 );
nuclear@0 541 firstChild = lastChild = addThis;
nuclear@0 542
nuclear@0 543 addThis->prev = 0;
nuclear@0 544 addThis->next = 0;
nuclear@0 545 }
nuclear@0 546 addThis->parent = this;
nuclear@0 547 return addThis;
nuclear@0 548 }
nuclear@0 549
nuclear@0 550
nuclear@0 551 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
nuclear@0 552 {
nuclear@0 553 if ( firstChild ) {
nuclear@0 554 TIXMLASSERT( lastChild );
nuclear@0 555 TIXMLASSERT( firstChild->prev == 0 );
nuclear@0 556
nuclear@0 557 firstChild->prev = addThis;
nuclear@0 558 addThis->next = firstChild;
nuclear@0 559 firstChild = addThis;
nuclear@0 560
nuclear@0 561 addThis->prev = 0;
nuclear@0 562 }
nuclear@0 563 else {
nuclear@0 564 TIXMLASSERT( lastChild == 0 );
nuclear@0 565 firstChild = lastChild = addThis;
nuclear@0 566
nuclear@0 567 addThis->prev = 0;
nuclear@0 568 addThis->next = 0;
nuclear@0 569 }
nuclear@0 570 addThis->parent = this;
nuclear@0 571 return addThis;
nuclear@0 572 }
nuclear@0 573
nuclear@0 574
nuclear@0 575 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
nuclear@0 576 {
nuclear@0 577 TIXMLASSERT( afterThis->parent == this );
nuclear@0 578 if ( afterThis->parent != this )
nuclear@0 579 return 0;
nuclear@0 580
nuclear@0 581 if ( afterThis->next == 0 ) {
nuclear@0 582 // The last node or the only node.
nuclear@0 583 return InsertEndChild( addThis );
nuclear@0 584 }
nuclear@0 585 addThis->prev = afterThis;
nuclear@0 586 addThis->next = afterThis->next;
nuclear@0 587 afterThis->next->prev = addThis;
nuclear@0 588 afterThis->next = addThis;
nuclear@0 589 addThis->parent = this;
nuclear@0 590 return addThis;
nuclear@0 591 }
nuclear@0 592
nuclear@0 593
nuclear@0 594
nuclear@0 595
nuclear@0 596 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
nuclear@0 597 {
nuclear@0 598 for( XMLNode* node=firstChild; node; node=node->next ) {
nuclear@0 599 XMLElement* element = node->ToElement();
nuclear@0 600 if ( element ) {
nuclear@0 601 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
nuclear@0 602 return element;
nuclear@0 603 }
nuclear@0 604 }
nuclear@0 605 }
nuclear@0 606 return 0;
nuclear@0 607 }
nuclear@0 608
nuclear@0 609
nuclear@0 610 const XMLElement* XMLNode::LastChildElement( const char* value ) const
nuclear@0 611 {
nuclear@0 612 for( XMLNode* node=lastChild; node; node=node->prev ) {
nuclear@0 613 XMLElement* element = node->ToElement();
nuclear@0 614 if ( element ) {
nuclear@0 615 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
nuclear@0 616 return element;
nuclear@0 617 }
nuclear@0 618 }
nuclear@0 619 }
nuclear@0 620 return 0;
nuclear@0 621 }
nuclear@0 622
nuclear@0 623
nuclear@0 624 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
nuclear@0 625 {
nuclear@0 626 for( XMLNode* element=this->next; element; element = element->next ) {
nuclear@0 627 if ( element->ToElement()
nuclear@0 628 && (!value || XMLUtil::StringEqual( value, element->Value() )))
nuclear@0 629 {
nuclear@0 630 return element->ToElement();
nuclear@0 631 }
nuclear@0 632 }
nuclear@0 633 return 0;
nuclear@0 634 }
nuclear@0 635
nuclear@0 636
nuclear@0 637 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
nuclear@0 638 {
nuclear@0 639 for( XMLNode* element=this->prev; element; element = element->prev ) {
nuclear@0 640 if ( element->ToElement()
nuclear@0 641 && (!value || XMLUtil::StringEqual( value, element->Value() )))
nuclear@0 642 {
nuclear@0 643 return element->ToElement();
nuclear@0 644 }
nuclear@0 645 }
nuclear@0 646 return 0;
nuclear@0 647 }
nuclear@0 648
nuclear@0 649
nuclear@0 650 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
nuclear@0 651 {
nuclear@0 652 // This is a recursive method, but thinking about it "at the current level"
nuclear@0 653 // it is a pretty simple flat list:
nuclear@0 654 // <foo/>
nuclear@0 655 // <!-- comment -->
nuclear@0 656 //
nuclear@0 657 // With a special case:
nuclear@0 658 // <foo>
nuclear@0 659 // </foo>
nuclear@0 660 // <!-- comment -->
nuclear@0 661 //
nuclear@0 662 // Where the closing element (/foo) *must* be the next thing after the opening
nuclear@0 663 // element, and the names must match. BUT the tricky bit is that the closing
nuclear@0 664 // element will be read by the child.
nuclear@0 665 //
nuclear@0 666 // 'endTag' is the end tag for this node, it is returned by a call to a child.
nuclear@0 667 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
nuclear@0 668
nuclear@0 669 while( p && *p ) {
nuclear@0 670 XMLNode* node = 0;
nuclear@0 671
nuclear@0 672 p = document->Identify( p, &node );
nuclear@0 673 if ( p == 0 || node == 0 ) {
nuclear@0 674 break;
nuclear@0 675 }
nuclear@0 676
nuclear@0 677 StrPair endTag;
nuclear@0 678 p = node->ParseDeep( p, &endTag );
nuclear@0 679 if ( !p ) {
nuclear@0 680 DELETE_NODE( node );
nuclear@0 681 node = 0;
nuclear@0 682 if ( !document->Error() ) {
nuclear@0 683 document->SetError( XML_ERROR_PARSING, 0, 0 );
nuclear@0 684 }
nuclear@0 685 break;
nuclear@0 686 }
nuclear@0 687
nuclear@0 688 // We read the end tag. Return it to the parent.
nuclear@0 689 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
nuclear@0 690 if ( parentEnd ) {
nuclear@0 691 *parentEnd = ((XMLElement*)node)->value;
nuclear@0 692 }
nuclear@0 693 DELETE_NODE( node );
nuclear@0 694 return p;
nuclear@0 695 }
nuclear@0 696
nuclear@0 697 // Handle an end tag returned to this level.
nuclear@0 698 // And handle a bunch of annoying errors.
nuclear@0 699 XMLElement* ele = node->ToElement();
nuclear@0 700 if ( ele ) {
nuclear@0 701 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
nuclear@0 702 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
nuclear@0 703 p = 0;
nuclear@0 704 }
nuclear@0 705 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
nuclear@0 706 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
nuclear@0 707 p = 0;
nuclear@0 708 }
nuclear@0 709 else if ( !endTag.Empty() ) {
nuclear@0 710 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
nuclear@0 711 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
nuclear@0 712 p = 0;
nuclear@0 713 }
nuclear@0 714 }
nuclear@0 715 }
nuclear@0 716 if ( p == 0 ) {
nuclear@0 717 DELETE_NODE( node );
nuclear@0 718 node = 0;
nuclear@0 719 }
nuclear@0 720 if ( node ) {
nuclear@0 721 this->InsertEndChild( node );
nuclear@0 722 }
nuclear@0 723 }
nuclear@0 724 return 0;
nuclear@0 725 }
nuclear@0 726
nuclear@0 727 // --------- XMLText ---------- //
nuclear@0 728 char* XMLText::ParseDeep( char* p, StrPair* )
nuclear@0 729 {
nuclear@0 730 const char* start = p;
nuclear@0 731 if ( this->CData() ) {
nuclear@0 732 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
nuclear@0 733 if ( !p ) {
nuclear@0 734 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
nuclear@0 735 }
nuclear@0 736 return p;
nuclear@0 737 }
nuclear@0 738 else {
nuclear@0 739 p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
nuclear@0 740 if ( !p ) {
nuclear@0 741 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
nuclear@0 742 }
nuclear@0 743 if ( p && *p ) {
nuclear@0 744 return p-1;
nuclear@0 745 }
nuclear@0 746 }
nuclear@0 747 return 0;
nuclear@0 748 }
nuclear@0 749
nuclear@0 750
nuclear@0 751 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
nuclear@0 752 {
nuclear@0 753 if ( !doc ) {
nuclear@0 754 doc = document;
nuclear@0 755 }
nuclear@0 756 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 757 text->SetCData( this->CData() );
nuclear@0 758 return text;
nuclear@0 759 }
nuclear@0 760
nuclear@0 761
nuclear@0 762 bool XMLText::ShallowEqual( const XMLNode* compare ) const
nuclear@0 763 {
nuclear@0 764 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
nuclear@0 765 }
nuclear@0 766
nuclear@0 767
nuclear@0 768 bool XMLText::Accept( XMLVisitor* visitor ) const
nuclear@0 769 {
nuclear@0 770 return visitor->Visit( *this );
nuclear@0 771 }
nuclear@0 772
nuclear@0 773
nuclear@0 774 // --------- XMLComment ---------- //
nuclear@0 775
nuclear@0 776 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
nuclear@0 777 {
nuclear@0 778 }
nuclear@0 779
nuclear@0 780
nuclear@0 781 XMLComment::~XMLComment()
nuclear@0 782 {
nuclear@0 783 //printf( "~XMLComment\n" );
nuclear@0 784 }
nuclear@0 785
nuclear@0 786
nuclear@0 787 char* XMLComment::ParseDeep( char* p, StrPair* )
nuclear@0 788 {
nuclear@0 789 // Comment parses as text.
nuclear@0 790 const char* start = p;
nuclear@0 791 p = value.ParseText( p, "-->", StrPair::COMMENT );
nuclear@0 792 if ( p == 0 ) {
nuclear@0 793 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
nuclear@0 794 }
nuclear@0 795 return p;
nuclear@0 796 }
nuclear@0 797
nuclear@0 798
nuclear@0 799 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
nuclear@0 800 {
nuclear@0 801 if ( !doc ) {
nuclear@0 802 doc = document;
nuclear@0 803 }
nuclear@0 804 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 805 return comment;
nuclear@0 806 }
nuclear@0 807
nuclear@0 808
nuclear@0 809 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
nuclear@0 810 {
nuclear@0 811 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
nuclear@0 812 }
nuclear@0 813
nuclear@0 814
nuclear@0 815 bool XMLComment::Accept( XMLVisitor* visitor ) const
nuclear@0 816 {
nuclear@0 817 return visitor->Visit( *this );
nuclear@0 818 }
nuclear@0 819
nuclear@0 820
nuclear@0 821 // --------- XMLDeclaration ---------- //
nuclear@0 822
nuclear@0 823 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
nuclear@0 824 {
nuclear@0 825 }
nuclear@0 826
nuclear@0 827
nuclear@0 828 XMLDeclaration::~XMLDeclaration()
nuclear@0 829 {
nuclear@0 830 //printf( "~XMLDeclaration\n" );
nuclear@0 831 }
nuclear@0 832
nuclear@0 833
nuclear@0 834 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
nuclear@0 835 {
nuclear@0 836 // Declaration parses as text.
nuclear@0 837 const char* start = p;
nuclear@0 838 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
nuclear@0 839 if ( p == 0 ) {
nuclear@0 840 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
nuclear@0 841 }
nuclear@0 842 return p;
nuclear@0 843 }
nuclear@0 844
nuclear@0 845
nuclear@0 846 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
nuclear@0 847 {
nuclear@0 848 if ( !doc ) {
nuclear@0 849 doc = document;
nuclear@0 850 }
nuclear@0 851 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 852 return dec;
nuclear@0 853 }
nuclear@0 854
nuclear@0 855
nuclear@0 856 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
nuclear@0 857 {
nuclear@0 858 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
nuclear@0 859 }
nuclear@0 860
nuclear@0 861
nuclear@0 862
nuclear@0 863 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
nuclear@0 864 {
nuclear@0 865 return visitor->Visit( *this );
nuclear@0 866 }
nuclear@0 867
nuclear@0 868 // --------- XMLUnknown ---------- //
nuclear@0 869
nuclear@0 870 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
nuclear@0 871 {
nuclear@0 872 }
nuclear@0 873
nuclear@0 874
nuclear@0 875 XMLUnknown::~XMLUnknown()
nuclear@0 876 {
nuclear@0 877 }
nuclear@0 878
nuclear@0 879
nuclear@0 880 char* XMLUnknown::ParseDeep( char* p, StrPair* )
nuclear@0 881 {
nuclear@0 882 // Unknown parses as text.
nuclear@0 883 const char* start = p;
nuclear@0 884
nuclear@0 885 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
nuclear@0 886 if ( !p ) {
nuclear@0 887 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
nuclear@0 888 }
nuclear@0 889 return p;
nuclear@0 890 }
nuclear@0 891
nuclear@0 892
nuclear@0 893 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
nuclear@0 894 {
nuclear@0 895 if ( !doc ) {
nuclear@0 896 doc = document;
nuclear@0 897 }
nuclear@0 898 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 899 return text;
nuclear@0 900 }
nuclear@0 901
nuclear@0 902
nuclear@0 903 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
nuclear@0 904 {
nuclear@0 905 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
nuclear@0 906 }
nuclear@0 907
nuclear@0 908
nuclear@0 909 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
nuclear@0 910 {
nuclear@0 911 return visitor->Visit( *this );
nuclear@0 912 }
nuclear@0 913
nuclear@0 914 // --------- XMLAttribute ---------- //
nuclear@0 915 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
nuclear@0 916 {
nuclear@0 917 p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
nuclear@0 918 if ( !p || !*p ) return 0;
nuclear@0 919
nuclear@0 920 char endTag[2] = { *p, 0 };
nuclear@0 921 ++p;
nuclear@0 922 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
nuclear@0 923 //if ( value.Empty() ) return 0;
nuclear@0 924 return p;
nuclear@0 925 }
nuclear@0 926
nuclear@0 927
nuclear@0 928 void XMLAttribute::SetName( const char* n )
nuclear@0 929 {
nuclear@0 930 name.SetStr( n );
nuclear@0 931 }
nuclear@0 932
nuclear@0 933
nuclear@0 934 int XMLAttribute::QueryIntValue( int* value ) const
nuclear@0 935 {
nuclear@0 936 if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
nuclear@0 937 return XML_NO_ERROR;
nuclear@0 938 return XML_WRONG_ATTRIBUTE_TYPE;
nuclear@0 939 }
nuclear@0 940
nuclear@0 941
nuclear@0 942 int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
nuclear@0 943 {
nuclear@0 944 if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
nuclear@0 945 return XML_NO_ERROR;
nuclear@0 946 return XML_WRONG_ATTRIBUTE_TYPE;
nuclear@0 947 }
nuclear@0 948
nuclear@0 949
nuclear@0 950 int XMLAttribute::QueryBoolValue( bool* value ) const
nuclear@0 951 {
nuclear@0 952 int ival = -1;
nuclear@0 953 QueryIntValue( &ival );
nuclear@0 954
nuclear@0 955 if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
nuclear@0 956 *value = true;
nuclear@0 957 return XML_NO_ERROR;
nuclear@0 958 }
nuclear@0 959 else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
nuclear@0 960 *value = false;
nuclear@0 961 return XML_NO_ERROR;
nuclear@0 962 }
nuclear@0 963 return XML_WRONG_ATTRIBUTE_TYPE;
nuclear@0 964 }
nuclear@0 965
nuclear@0 966
nuclear@0 967 int XMLAttribute::QueryDoubleValue( double* value ) const
nuclear@0 968 {
nuclear@0 969 if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
nuclear@0 970 return XML_NO_ERROR;
nuclear@0 971 return XML_WRONG_ATTRIBUTE_TYPE;
nuclear@0 972 }
nuclear@0 973
nuclear@0 974
nuclear@0 975 int XMLAttribute::QueryFloatValue( float* value ) const
nuclear@0 976 {
nuclear@0 977 if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
nuclear@0 978 return XML_NO_ERROR;
nuclear@0 979 return XML_WRONG_ATTRIBUTE_TYPE;
nuclear@0 980 }
nuclear@0 981
nuclear@0 982
nuclear@0 983 void XMLAttribute::SetAttribute( const char* v )
nuclear@0 984 {
nuclear@0 985 value.SetStr( v );
nuclear@0 986 }
nuclear@0 987
nuclear@0 988
nuclear@0 989 void XMLAttribute::SetAttribute( int v )
nuclear@0 990 {
nuclear@0 991 char buf[BUF_SIZE];
nuclear@0 992 TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );
nuclear@0 993 value.SetStr( buf );
nuclear@0 994 }
nuclear@0 995
nuclear@0 996
nuclear@0 997 void XMLAttribute::SetAttribute( unsigned v )
nuclear@0 998 {
nuclear@0 999 char buf[BUF_SIZE];
nuclear@0 1000 TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );
nuclear@0 1001 value.SetStr( buf );
nuclear@0 1002 }
nuclear@0 1003
nuclear@0 1004
nuclear@0 1005 void XMLAttribute::SetAttribute( bool v )
nuclear@0 1006 {
nuclear@0 1007 char buf[BUF_SIZE];
nuclear@0 1008 TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );
nuclear@0 1009 value.SetStr( buf );
nuclear@0 1010 }
nuclear@0 1011
nuclear@0 1012 void XMLAttribute::SetAttribute( double v )
nuclear@0 1013 {
nuclear@0 1014 char buf[BUF_SIZE];
nuclear@0 1015 TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );
nuclear@0 1016 value.SetStr( buf );
nuclear@0 1017 }
nuclear@0 1018
nuclear@0 1019 void XMLAttribute::SetAttribute( float v )
nuclear@0 1020 {
nuclear@0 1021 char buf[BUF_SIZE];
nuclear@0 1022 TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );
nuclear@0 1023 value.SetStr( buf );
nuclear@0 1024 }
nuclear@0 1025
nuclear@0 1026
nuclear@0 1027 // --------- XMLElement ---------- //
nuclear@0 1028 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
nuclear@0 1029 closingType( 0 ),
nuclear@0 1030 rootAttribute( 0 )
nuclear@0 1031 {
nuclear@0 1032 }
nuclear@0 1033
nuclear@0 1034
nuclear@0 1035 XMLElement::~XMLElement()
nuclear@0 1036 {
nuclear@0 1037 while( rootAttribute ) {
nuclear@0 1038 XMLAttribute* next = rootAttribute->next;
nuclear@0 1039 DELETE_ATTRIBUTE( rootAttribute );
nuclear@0 1040 rootAttribute = next;
nuclear@0 1041 }
nuclear@0 1042 }
nuclear@0 1043
nuclear@0 1044
nuclear@0 1045 XMLAttribute* XMLElement::FindAttribute( const char* name )
nuclear@0 1046 {
nuclear@0 1047 XMLAttribute* a = 0;
nuclear@0 1048 for( a=rootAttribute; a; a = a->next ) {
nuclear@0 1049 if ( XMLUtil::StringEqual( a->Name(), name ) )
nuclear@0 1050 return a;
nuclear@0 1051 }
nuclear@0 1052 return 0;
nuclear@0 1053 }
nuclear@0 1054
nuclear@0 1055
nuclear@0 1056 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
nuclear@0 1057 {
nuclear@0 1058 XMLAttribute* a = 0;
nuclear@0 1059 for( a=rootAttribute; a; a = a->next ) {
nuclear@0 1060 if ( XMLUtil::StringEqual( a->Name(), name ) )
nuclear@0 1061 return a;
nuclear@0 1062 }
nuclear@0 1063 return 0;
nuclear@0 1064 }
nuclear@0 1065
nuclear@0 1066
nuclear@0 1067 const char* XMLElement::Attribute( const char* name, const char* value ) const
nuclear@0 1068 {
nuclear@0 1069 const XMLAttribute* a = FindAttribute( name );
nuclear@0 1070 if ( !a )
nuclear@0 1071 return 0;
nuclear@0 1072 if ( !value || XMLUtil::StringEqual( a->Value(), value ))
nuclear@0 1073 return a->Value();
nuclear@0 1074 return 0;
nuclear@0 1075 }
nuclear@0 1076
nuclear@0 1077
nuclear@0 1078 const char* XMLElement::GetText() const
nuclear@0 1079 {
nuclear@0 1080 if ( FirstChild() && FirstChild()->ToText() ) {
nuclear@0 1081 return FirstChild()->ToText()->Value();
nuclear@0 1082 }
nuclear@0 1083 return 0;
nuclear@0 1084 }
nuclear@0 1085
nuclear@0 1086
nuclear@0 1087 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
nuclear@0 1088 {
nuclear@0 1089 XMLAttribute* last = 0;
nuclear@0 1090 XMLAttribute* attrib = 0;
nuclear@0 1091 for( attrib = rootAttribute;
nuclear@0 1092 attrib;
nuclear@0 1093 last = attrib, attrib = attrib->next )
nuclear@0 1094 {
nuclear@0 1095 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
nuclear@0 1096 break;
nuclear@0 1097 }
nuclear@0 1098 }
nuclear@0 1099 if ( !attrib ) {
nuclear@0 1100 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
nuclear@0 1101 attrib->memPool = &document->attributePool;
nuclear@0 1102 if ( last ) {
nuclear@0 1103 last->next = attrib;
nuclear@0 1104 }
nuclear@0 1105 else {
nuclear@0 1106 rootAttribute = attrib;
nuclear@0 1107 }
nuclear@0 1108 attrib->SetName( name );
nuclear@0 1109 }
nuclear@0 1110 return attrib;
nuclear@0 1111 }
nuclear@0 1112
nuclear@0 1113
nuclear@0 1114 void XMLElement::DeleteAttribute( const char* name )
nuclear@0 1115 {
nuclear@0 1116 XMLAttribute* prev = 0;
nuclear@0 1117 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
nuclear@0 1118 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
nuclear@0 1119 if ( prev ) {
nuclear@0 1120 prev->next = a->next;
nuclear@0 1121 }
nuclear@0 1122 else {
nuclear@0 1123 rootAttribute = a->next;
nuclear@0 1124 }
nuclear@0 1125 DELETE_ATTRIBUTE( a );
nuclear@0 1126 break;
nuclear@0 1127 }
nuclear@0 1128 prev = a;
nuclear@0 1129 }
nuclear@0 1130 }
nuclear@0 1131
nuclear@0 1132
nuclear@0 1133 char* XMLElement::ParseAttributes( char* p )
nuclear@0 1134 {
nuclear@0 1135 const char* start = p;
nuclear@0 1136 XMLAttribute* prevAttribute = 0;
nuclear@0 1137
nuclear@0 1138 // Read the attributes.
nuclear@0 1139 while( p ) {
nuclear@0 1140 p = XMLUtil::SkipWhiteSpace( p );
nuclear@0 1141 if ( !p || !(*p) ) {
nuclear@0 1142 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
nuclear@0 1143 return 0;
nuclear@0 1144 }
nuclear@0 1145
nuclear@0 1146 // attribute.
nuclear@0 1147 if ( XMLUtil::IsAlpha( *p ) ) {
nuclear@0 1148 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
nuclear@0 1149 attrib->memPool = &document->attributePool;
nuclear@0 1150
nuclear@0 1151 p = attrib->ParseDeep( p, document->ProcessEntities() );
nuclear@0 1152 if ( !p || Attribute( attrib->Name() ) ) {
nuclear@0 1153 DELETE_ATTRIBUTE( attrib );
nuclear@0 1154 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
nuclear@0 1155 return 0;
nuclear@0 1156 }
nuclear@0 1157 // There is a minor bug here: if the attribute in the source xml
nuclear@0 1158 // document is duplicated, it will not be detected and the
nuclear@0 1159 // attribute will be doubly added. However, tracking the 'prevAttribute'
nuclear@0 1160 // avoids re-scanning the attribute list. Preferring performance for
nuclear@0 1161 // now, may reconsider in the future.
nuclear@0 1162 if ( prevAttribute ) {
nuclear@0 1163 prevAttribute->next = attrib;
nuclear@0 1164 }
nuclear@0 1165 else {
nuclear@0 1166 rootAttribute = attrib;
nuclear@0 1167 }
nuclear@0 1168 prevAttribute = attrib;
nuclear@0 1169 }
nuclear@0 1170 // end of the tag
nuclear@0 1171 else if ( *p == '/' && *(p+1) == '>' ) {
nuclear@0 1172 closingType = CLOSED;
nuclear@0 1173 return p+2; // done; sealed element.
nuclear@0 1174 }
nuclear@0 1175 // end of the tag
nuclear@0 1176 else if ( *p == '>' ) {
nuclear@0 1177 ++p;
nuclear@0 1178 break;
nuclear@0 1179 }
nuclear@0 1180 else {
nuclear@0 1181 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
nuclear@0 1182 return 0;
nuclear@0 1183 }
nuclear@0 1184 }
nuclear@0 1185 return p;
nuclear@0 1186 }
nuclear@0 1187
nuclear@0 1188
nuclear@0 1189 //
nuclear@0 1190 // <ele></ele>
nuclear@0 1191 // <ele>foo<b>bar</b></ele>
nuclear@0 1192 //
nuclear@0 1193 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
nuclear@0 1194 {
nuclear@0 1195 // Read the element name.
nuclear@0 1196 p = XMLUtil::SkipWhiteSpace( p );
nuclear@0 1197 if ( !p ) return 0;
nuclear@0 1198
nuclear@0 1199 // The closing element is the </element> form. It is
nuclear@0 1200 // parsed just like a regular element then deleted from
nuclear@0 1201 // the DOM.
nuclear@0 1202 if ( *p == '/' ) {
nuclear@0 1203 closingType = CLOSING;
nuclear@0 1204 ++p;
nuclear@0 1205 }
nuclear@0 1206
nuclear@0 1207 p = value.ParseName( p );
nuclear@0 1208 if ( value.Empty() ) return 0;
nuclear@0 1209
nuclear@0 1210 p = ParseAttributes( p );
nuclear@0 1211 if ( !p || !*p || closingType )
nuclear@0 1212 return p;
nuclear@0 1213
nuclear@0 1214 p = XMLNode::ParseDeep( p, strPair );
nuclear@0 1215 return p;
nuclear@0 1216 }
nuclear@0 1217
nuclear@0 1218
nuclear@0 1219
nuclear@0 1220 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
nuclear@0 1221 {
nuclear@0 1222 if ( !doc ) {
nuclear@0 1223 doc = document;
nuclear@0 1224 }
nuclear@0 1225 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 1226 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
nuclear@0 1227 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
nuclear@0 1228 }
nuclear@0 1229 return element;
nuclear@0 1230 }
nuclear@0 1231
nuclear@0 1232
nuclear@0 1233 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
nuclear@0 1234 {
nuclear@0 1235 const XMLElement* other = compare->ToElement();
nuclear@0 1236 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
nuclear@0 1237
nuclear@0 1238 const XMLAttribute* a=FirstAttribute();
nuclear@0 1239 const XMLAttribute* b=other->FirstAttribute();
nuclear@0 1240
nuclear@0 1241 while ( a && b ) {
nuclear@0 1242 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
nuclear@0 1243 return false;
nuclear@0 1244 }
nuclear@0 1245 }
nuclear@0 1246 if ( a || b ) {
nuclear@0 1247 // different count
nuclear@0 1248 return false;
nuclear@0 1249 }
nuclear@0 1250 return true;
nuclear@0 1251 }
nuclear@0 1252 return false;
nuclear@0 1253 }
nuclear@0 1254
nuclear@0 1255
nuclear@0 1256 bool XMLElement::Accept( XMLVisitor* visitor ) const
nuclear@0 1257 {
nuclear@0 1258 if ( visitor->VisitEnter( *this, rootAttribute ) )
nuclear@0 1259 {
nuclear@0 1260 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
nuclear@0 1261 {
nuclear@0 1262 if ( !node->Accept( visitor ) )
nuclear@0 1263 break;
nuclear@0 1264 }
nuclear@0 1265 }
nuclear@0 1266 return visitor->VisitExit( *this );
nuclear@0 1267 }
nuclear@0 1268
nuclear@0 1269
nuclear@0 1270 // --------- XMLDocument ----------- //
nuclear@0 1271 XMLDocument::XMLDocument( bool _processEntities ) :
nuclear@0 1272 XMLNode( 0 ),
nuclear@0 1273 writeBOM( false ),
nuclear@0 1274 processEntities( _processEntities ),
nuclear@0 1275 errorID( 0 ),
nuclear@0 1276 errorStr1( 0 ),
nuclear@0 1277 errorStr2( 0 ),
nuclear@0 1278 charBuffer( 0 )
nuclear@0 1279 {
nuclear@0 1280 document = this; // avoid warning about 'this' in initializer list
nuclear@0 1281 }
nuclear@0 1282
nuclear@0 1283
nuclear@0 1284 XMLDocument::~XMLDocument()
nuclear@0 1285 {
nuclear@0 1286 DeleteChildren();
nuclear@0 1287 delete [] charBuffer;
nuclear@0 1288
nuclear@0 1289 #if 0
nuclear@0 1290 textPool.Trace( "text" );
nuclear@0 1291 elementPool.Trace( "element" );
nuclear@0 1292 commentPool.Trace( "comment" );
nuclear@0 1293 attributePool.Trace( "attribute" );
nuclear@0 1294 #endif
nuclear@0 1295
nuclear@0 1296 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
nuclear@0 1297 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
nuclear@0 1298 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
nuclear@0 1299 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
nuclear@0 1300 }
nuclear@0 1301
nuclear@0 1302
nuclear@0 1303 void XMLDocument::InitDocument()
nuclear@0 1304 {
nuclear@0 1305 errorID = XML_NO_ERROR;
nuclear@0 1306 errorStr1 = 0;
nuclear@0 1307 errorStr2 = 0;
nuclear@0 1308
nuclear@0 1309 delete [] charBuffer;
nuclear@0 1310 charBuffer = 0;
nuclear@0 1311
nuclear@0 1312 }
nuclear@0 1313
nuclear@0 1314
nuclear@0 1315 XMLElement* XMLDocument::NewElement( const char* name )
nuclear@0 1316 {
nuclear@0 1317 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
nuclear@0 1318 ele->memPool = &elementPool;
nuclear@0 1319 ele->SetName( name );
nuclear@0 1320 return ele;
nuclear@0 1321 }
nuclear@0 1322
nuclear@0 1323
nuclear@0 1324 XMLComment* XMLDocument::NewComment( const char* str )
nuclear@0 1325 {
nuclear@0 1326 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
nuclear@0 1327 comment->memPool = &commentPool;
nuclear@0 1328 comment->SetValue( str );
nuclear@0 1329 return comment;
nuclear@0 1330 }
nuclear@0 1331
nuclear@0 1332
nuclear@0 1333 XMLText* XMLDocument::NewText( const char* str )
nuclear@0 1334 {
nuclear@0 1335 XMLText* text = new (textPool.Alloc()) XMLText( this );
nuclear@0 1336 text->memPool = &textPool;
nuclear@0 1337 text->SetValue( str );
nuclear@0 1338 return text;
nuclear@0 1339 }
nuclear@0 1340
nuclear@0 1341
nuclear@0 1342 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
nuclear@0 1343 {
nuclear@0 1344 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
nuclear@0 1345 dec->memPool = &commentPool;
nuclear@0 1346 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
nuclear@0 1347 return dec;
nuclear@0 1348 }
nuclear@0 1349
nuclear@0 1350
nuclear@0 1351 XMLUnknown* XMLDocument::NewUnknown( const char* str )
nuclear@0 1352 {
nuclear@0 1353 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
nuclear@0 1354 unk->memPool = &commentPool;
nuclear@0 1355 unk->SetValue( str );
nuclear@0 1356 return unk;
nuclear@0 1357 }
nuclear@0 1358
nuclear@0 1359
nuclear@0 1360 int XMLDocument::LoadFile( const char* filename )
nuclear@0 1361 {
nuclear@0 1362 DeleteChildren();
nuclear@0 1363 InitDocument();
nuclear@0 1364
nuclear@0 1365 #if defined(_MSC_VER)
nuclear@0 1366 #pragma warning ( push )
nuclear@0 1367 #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
nuclear@0 1368 #endif
nuclear@0 1369 FILE* fp = fopen( filename, "rb" );
nuclear@0 1370 #if defined(_MSC_VER)
nuclear@0 1371 #pragma warning ( pop )
nuclear@0 1372 #endif
nuclear@0 1373 if ( !fp ) {
nuclear@0 1374 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
nuclear@0 1375 return errorID;
nuclear@0 1376 }
nuclear@0 1377 LoadFile( fp );
nuclear@0 1378 fclose( fp );
nuclear@0 1379 return errorID;
nuclear@0 1380 }
nuclear@0 1381
nuclear@0 1382
nuclear@0 1383 int XMLDocument::LoadFile( FILE* fp )
nuclear@0 1384 {
nuclear@0 1385 DeleteChildren();
nuclear@0 1386 InitDocument();
nuclear@0 1387
nuclear@0 1388 fseek( fp, 0, SEEK_END );
nuclear@0 1389 unsigned size = ftell( fp );
nuclear@0 1390 fseek( fp, 0, SEEK_SET );
nuclear@0 1391
nuclear@0 1392 if ( size == 0 ) {
nuclear@0 1393 return errorID;
nuclear@0 1394 }
nuclear@0 1395
nuclear@0 1396 charBuffer = new char[size+1];
nuclear@0 1397 fread( charBuffer, size, 1, fp );
nuclear@0 1398 charBuffer[size] = 0;
nuclear@0 1399
nuclear@0 1400 const char* p = charBuffer;
nuclear@0 1401 p = XMLUtil::SkipWhiteSpace( p );
nuclear@0 1402 p = XMLUtil::ReadBOM( p, &writeBOM );
nuclear@0 1403 if ( !p || !*p ) {
nuclear@0 1404 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
nuclear@0 1405 return errorID;
nuclear@0 1406 }
nuclear@0 1407
nuclear@0 1408 ParseDeep( charBuffer + (p-charBuffer), 0 );
nuclear@0 1409 return errorID;
nuclear@0 1410 }
nuclear@0 1411
nuclear@0 1412
nuclear@0 1413 int XMLDocument::SaveFile( const char* filename )
nuclear@0 1414 {
nuclear@0 1415 #if defined(_MSC_VER)
nuclear@0 1416 #pragma warning ( push )
nuclear@0 1417 #pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated.
nuclear@0 1418 #endif
nuclear@0 1419 FILE* fp = fopen( filename, "w" );
nuclear@0 1420 #if defined(_MSC_VER)
nuclear@0 1421 #pragma warning ( pop )
nuclear@0 1422 #endif
nuclear@0 1423 if ( !fp ) {
nuclear@0 1424 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
nuclear@0 1425 return errorID;
nuclear@0 1426 }
nuclear@0 1427 SaveFile(fp);
nuclear@0 1428 fclose( fp );
nuclear@0 1429 return errorID;
nuclear@0 1430 }
nuclear@0 1431
nuclear@0 1432
nuclear@0 1433 int XMLDocument::SaveFile( FILE* fp )
nuclear@0 1434 {
nuclear@0 1435 XMLPrinter stream( fp );
nuclear@0 1436 Print( &stream );
nuclear@0 1437 return errorID;
nuclear@0 1438 }
nuclear@0 1439
nuclear@0 1440
nuclear@0 1441 int XMLDocument::Parse( const char* p )
nuclear@0 1442 {
nuclear@0 1443 DeleteChildren();
nuclear@0 1444 InitDocument();
nuclear@0 1445
nuclear@0 1446 if ( !p || !*p ) {
nuclear@0 1447 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
nuclear@0 1448 return errorID;
nuclear@0 1449 }
nuclear@0 1450 p = XMLUtil::SkipWhiteSpace( p );
nuclear@0 1451 p = XMLUtil::ReadBOM( p, &writeBOM );
nuclear@0 1452 if ( !p || !*p ) {
nuclear@0 1453 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
nuclear@0 1454 return errorID;
nuclear@0 1455 }
nuclear@0 1456
nuclear@0 1457 size_t len = strlen( p );
nuclear@0 1458 charBuffer = new char[ len+1 ];
nuclear@0 1459 memcpy( charBuffer, p, len+1 );
nuclear@0 1460
nuclear@0 1461
nuclear@0 1462 ParseDeep( charBuffer, 0 );
nuclear@0 1463 return errorID;
nuclear@0 1464 }
nuclear@0 1465
nuclear@0 1466
nuclear@0 1467 void XMLDocument::Print( XMLPrinter* streamer )
nuclear@0 1468 {
nuclear@0 1469 XMLPrinter stdStreamer( stdout );
nuclear@0 1470 if ( !streamer )
nuclear@0 1471 streamer = &stdStreamer;
nuclear@0 1472 Accept( streamer );
nuclear@0 1473 }
nuclear@0 1474
nuclear@0 1475
nuclear@0 1476 void XMLDocument::SetError( int error, const char* str1, const char* str2 )
nuclear@0 1477 {
nuclear@0 1478 errorID = error;
nuclear@0 1479 errorStr1 = str1;
nuclear@0 1480 errorStr2 = str2;
nuclear@0 1481 }
nuclear@0 1482
nuclear@0 1483
nuclear@0 1484 void XMLDocument::PrintError() const
nuclear@0 1485 {
nuclear@0 1486 if ( errorID ) {
nuclear@0 1487 static const int LEN = 20;
nuclear@0 1488 char buf1[LEN] = { 0 };
nuclear@0 1489 char buf2[LEN] = { 0 };
nuclear@0 1490
nuclear@0 1491 if ( errorStr1 ) {
nuclear@0 1492 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
nuclear@0 1493 }
nuclear@0 1494 if ( errorStr2 ) {
nuclear@0 1495 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
nuclear@0 1496 }
nuclear@0 1497
nuclear@0 1498 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
nuclear@0 1499 errorID, buf1, buf2 );
nuclear@0 1500 }
nuclear@0 1501 }
nuclear@0 1502
nuclear@0 1503
nuclear@0 1504 XMLPrinter::XMLPrinter( FILE* file ) :
nuclear@0 1505 elementJustOpened( false ),
nuclear@0 1506 firstElement( true ),
nuclear@0 1507 fp( file ),
nuclear@0 1508 depth( 0 ),
nuclear@0 1509 textDepth( -1 ),
nuclear@0 1510 processEntities( true )
nuclear@0 1511 {
nuclear@0 1512 for( int i=0; i<ENTITY_RANGE; ++i ) {
nuclear@0 1513 entityFlag[i] = false;
nuclear@0 1514 restrictedEntityFlag[i] = false;
nuclear@0 1515 }
nuclear@0 1516 for( int i=0; i<NUM_ENTITIES; ++i ) {
nuclear@0 1517 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
nuclear@0 1518 if ( entities[i].value < ENTITY_RANGE ) {
nuclear@0 1519 entityFlag[ (int)entities[i].value ] = true;
nuclear@0 1520 }
nuclear@0 1521 }
nuclear@0 1522 restrictedEntityFlag[(int)'&'] = true;
nuclear@0 1523 restrictedEntityFlag[(int)'<'] = true;
nuclear@0 1524 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
nuclear@0 1525 buffer.Push( 0 );
nuclear@0 1526 }
nuclear@0 1527
nuclear@0 1528
nuclear@0 1529 void XMLPrinter::Print( const char* format, ... )
nuclear@0 1530 {
nuclear@0 1531 va_list va;
nuclear@0 1532 va_start( va, format );
nuclear@0 1533
nuclear@0 1534 if ( fp ) {
nuclear@0 1535 vfprintf( fp, format, va );
nuclear@0 1536 }
nuclear@0 1537 else {
nuclear@0 1538 // This seems brutally complex. Haven't figured out a better
nuclear@0 1539 // way on windows.
nuclear@0 1540 #ifdef _MSC_VER
nuclear@0 1541 int len = -1;
nuclear@0 1542 int expand = 1000;
nuclear@0 1543 while ( len < 0 ) {
nuclear@0 1544 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
nuclear@0 1545 if ( len < 0 ) {
nuclear@0 1546 expand *= 3/2;
nuclear@0 1547 accumulator.PushArr( expand );
nuclear@0 1548 }
nuclear@0 1549 }
nuclear@0 1550 char* p = buffer.PushArr( len ) - 1;
nuclear@0 1551 memcpy( p, accumulator.Mem(), len+1 );
nuclear@0 1552 #else
nuclear@0 1553 int len = vsnprintf( 0, 0, format, va );
nuclear@0 1554 // Close out and re-start the va-args
nuclear@0 1555 va_end( va );
nuclear@0 1556 va_start( va, format );
nuclear@0 1557 char* p = buffer.PushArr( len ) - 1;
nuclear@0 1558 vsnprintf( p, len+1, format, va );
nuclear@0 1559 #endif
nuclear@0 1560 }
nuclear@0 1561 va_end( va );
nuclear@0 1562 }
nuclear@0 1563
nuclear@0 1564
nuclear@0 1565 void XMLPrinter::PrintSpace( int depth )
nuclear@0 1566 {
nuclear@0 1567 for( int i=0; i<depth; ++i ) {
nuclear@0 1568 Print( " " );
nuclear@0 1569 }
nuclear@0 1570 }
nuclear@0 1571
nuclear@0 1572
nuclear@0 1573 void XMLPrinter::PrintString( const char* p, bool restricted )
nuclear@0 1574 {
nuclear@0 1575 // Look for runs of bytes between entities to print.
nuclear@0 1576 const char* q = p;
nuclear@0 1577 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
nuclear@0 1578
nuclear@0 1579 if ( processEntities ) {
nuclear@0 1580 while ( *q ) {
nuclear@0 1581 // Remember, char is sometimes signed. (How many times has that bitten me?)
nuclear@0 1582 if ( *q > 0 && *q < ENTITY_RANGE ) {
nuclear@0 1583 // Check for entities. If one is found, flush
nuclear@0 1584 // the stream up until the entity, write the
nuclear@0 1585 // entity, and keep looking.
nuclear@0 1586 if ( flag[(unsigned)(*q)] ) {
nuclear@0 1587 while ( p < q ) {
nuclear@0 1588 Print( "%c", *p );
nuclear@0 1589 ++p;
nuclear@0 1590 }
nuclear@0 1591 for( int i=0; i<NUM_ENTITIES; ++i ) {
nuclear@0 1592 if ( entities[i].value == *q ) {
nuclear@0 1593 Print( "&%s;", entities[i].pattern );
nuclear@0 1594 break;
nuclear@0 1595 }
nuclear@0 1596 }
nuclear@0 1597 ++p;
nuclear@0 1598 }
nuclear@0 1599 }
nuclear@0 1600 ++q;
nuclear@0 1601 }
nuclear@0 1602 }
nuclear@0 1603 // Flush the remaining string. This will be the entire
nuclear@0 1604 // string if an entity wasn't found.
nuclear@0 1605 if ( !processEntities || (q-p > 0) ) {
nuclear@0 1606 Print( "%s", p );
nuclear@0 1607 }
nuclear@0 1608 }
nuclear@0 1609
nuclear@0 1610
nuclear@0 1611 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
nuclear@0 1612 {
nuclear@0 1613 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
nuclear@0 1614 if ( writeBOM ) {
nuclear@0 1615 Print( "%s", bom );
nuclear@0 1616 }
nuclear@0 1617 if ( writeDec ) {
nuclear@0 1618 PushDeclaration( "xml version=\"1.0\"" );
nuclear@0 1619 }
nuclear@0 1620 }
nuclear@0 1621
nuclear@0 1622
nuclear@0 1623 void XMLPrinter::OpenElement( const char* name )
nuclear@0 1624 {
nuclear@0 1625 if ( elementJustOpened ) {
nuclear@0 1626 SealElement();
nuclear@0 1627 }
nuclear@0 1628 stack.Push( name );
nuclear@0 1629
nuclear@0 1630 if ( textDepth < 0 && !firstElement ) {
nuclear@0 1631 Print( "\n" );
nuclear@0 1632 PrintSpace( depth );
nuclear@0 1633 }
nuclear@0 1634
nuclear@0 1635 Print( "<%s", name );
nuclear@0 1636 elementJustOpened = true;
nuclear@0 1637 firstElement = false;
nuclear@0 1638 ++depth;
nuclear@0 1639 }
nuclear@0 1640
nuclear@0 1641
nuclear@0 1642 void XMLPrinter::PushAttribute( const char* name, const char* value )
nuclear@0 1643 {
nuclear@0 1644 TIXMLASSERT( elementJustOpened );
nuclear@0 1645 Print( " %s=\"", name );
nuclear@0 1646 PrintString( value, false );
nuclear@0 1647 Print( "\"" );
nuclear@0 1648 }
nuclear@0 1649
nuclear@0 1650
nuclear@0 1651 void XMLPrinter::PushAttribute( const char* name, int v )
nuclear@0 1652 {
nuclear@0 1653 char buf[BUF_SIZE];
nuclear@0 1654 TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );
nuclear@0 1655 PushAttribute( name, buf );
nuclear@0 1656 }
nuclear@0 1657
nuclear@0 1658
nuclear@0 1659 void XMLPrinter::PushAttribute( const char* name, unsigned v )
nuclear@0 1660 {
nuclear@0 1661 char buf[BUF_SIZE];
nuclear@0 1662 TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );
nuclear@0 1663 PushAttribute( name, buf );
nuclear@0 1664 }
nuclear@0 1665
nuclear@0 1666
nuclear@0 1667 void XMLPrinter::PushAttribute( const char* name, bool v )
nuclear@0 1668 {
nuclear@0 1669 char buf[BUF_SIZE];
nuclear@0 1670 TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );
nuclear@0 1671 PushAttribute( name, buf );
nuclear@0 1672 }
nuclear@0 1673
nuclear@0 1674
nuclear@0 1675 void XMLPrinter::PushAttribute( const char* name, double v )
nuclear@0 1676 {
nuclear@0 1677 char buf[BUF_SIZE];
nuclear@0 1678 TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );
nuclear@0 1679 PushAttribute( name, buf );
nuclear@0 1680 }
nuclear@0 1681
nuclear@0 1682
nuclear@0 1683 void XMLPrinter::CloseElement()
nuclear@0 1684 {
nuclear@0 1685 --depth;
nuclear@0 1686 const char* name = stack.Pop();
nuclear@0 1687
nuclear@0 1688 if ( elementJustOpened ) {
nuclear@0 1689 Print( "/>" );
nuclear@0 1690 }
nuclear@0 1691 else {
nuclear@0 1692 if ( textDepth < 0 ) {
nuclear@0 1693 Print( "\n" );
nuclear@0 1694 PrintSpace( depth );
nuclear@0 1695 }
nuclear@0 1696 Print( "</%s>", name );
nuclear@0 1697 }
nuclear@0 1698
nuclear@0 1699 if ( textDepth == depth )
nuclear@0 1700 textDepth = -1;
nuclear@0 1701 if ( depth == 0 )
nuclear@0 1702 Print( "\n" );
nuclear@0 1703 elementJustOpened = false;
nuclear@0 1704 }
nuclear@0 1705
nuclear@0 1706
nuclear@0 1707 void XMLPrinter::SealElement()
nuclear@0 1708 {
nuclear@0 1709 elementJustOpened = false;
nuclear@0 1710 Print( ">" );
nuclear@0 1711 }
nuclear@0 1712
nuclear@0 1713
nuclear@0 1714 void XMLPrinter::PushText( const char* text, bool cdata )
nuclear@0 1715 {
nuclear@0 1716 textDepth = depth-1;
nuclear@0 1717
nuclear@0 1718 if ( elementJustOpened ) {
nuclear@0 1719 SealElement();
nuclear@0 1720 }
nuclear@0 1721 if ( cdata ) {
nuclear@0 1722 Print( "<![CDATA[" );
nuclear@0 1723 Print( "%s", text );
nuclear@0 1724 Print( "]]>" );
nuclear@0 1725 }
nuclear@0 1726 else {
nuclear@0 1727 PrintString( text, true );
nuclear@0 1728 }
nuclear@0 1729 }
nuclear@0 1730
nuclear@0 1731
nuclear@0 1732 void XMLPrinter::PushComment( const char* comment )
nuclear@0 1733 {
nuclear@0 1734 if ( elementJustOpened ) {
nuclear@0 1735 SealElement();
nuclear@0 1736 }
nuclear@0 1737 if ( textDepth < 0 && !firstElement ) {
nuclear@0 1738 Print( "\n" );
nuclear@0 1739 PrintSpace( depth );
nuclear@0 1740 }
nuclear@0 1741 firstElement = false;
nuclear@0 1742 Print( "<!--%s-->", comment );
nuclear@0 1743 }
nuclear@0 1744
nuclear@0 1745
nuclear@0 1746 void XMLPrinter::PushDeclaration( const char* value )
nuclear@0 1747 {
nuclear@0 1748 if ( elementJustOpened ) {
nuclear@0 1749 SealElement();
nuclear@0 1750 }
nuclear@0 1751 if ( textDepth < 0 && !firstElement) {
nuclear@0 1752 Print( "\n" );
nuclear@0 1753 PrintSpace( depth );
nuclear@0 1754 }
nuclear@0 1755 firstElement = false;
nuclear@0 1756 Print( "<?%s?>", value );
nuclear@0 1757 }
nuclear@0 1758
nuclear@0 1759
nuclear@0 1760 void XMLPrinter::PushUnknown( const char* value )
nuclear@0 1761 {
nuclear@0 1762 if ( elementJustOpened ) {
nuclear@0 1763 SealElement();
nuclear@0 1764 }
nuclear@0 1765 if ( textDepth < 0 && !firstElement ) {
nuclear@0 1766 Print( "\n" );
nuclear@0 1767 PrintSpace( depth );
nuclear@0 1768 }
nuclear@0 1769 firstElement = false;
nuclear@0 1770 Print( "<!%s>", value );
nuclear@0 1771 }
nuclear@0 1772
nuclear@0 1773
nuclear@0 1774 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
nuclear@0 1775 {
nuclear@0 1776 processEntities = doc.ProcessEntities();
nuclear@0 1777 if ( doc.HasBOM() ) {
nuclear@0 1778 PushHeader( true, false );
nuclear@0 1779 }
nuclear@0 1780 return true;
nuclear@0 1781 }
nuclear@0 1782
nuclear@0 1783
nuclear@0 1784 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
nuclear@0 1785 {
nuclear@0 1786 OpenElement( element.Name() );
nuclear@0 1787 while ( attribute ) {
nuclear@0 1788 PushAttribute( attribute->Name(), attribute->Value() );
nuclear@0 1789 attribute = attribute->Next();
nuclear@0 1790 }
nuclear@0 1791 return true;
nuclear@0 1792 }
nuclear@0 1793
nuclear@0 1794
nuclear@0 1795 bool XMLPrinter::VisitExit( const XMLElement& )
nuclear@0 1796 {
nuclear@0 1797 CloseElement();
nuclear@0 1798 return true;
nuclear@0 1799 }
nuclear@0 1800
nuclear@0 1801
nuclear@0 1802 bool XMLPrinter::Visit( const XMLText& text )
nuclear@0 1803 {
nuclear@0 1804 PushText( text.Value(), text.CData() );
nuclear@0 1805 return true;
nuclear@0 1806 }
nuclear@0 1807
nuclear@0 1808
nuclear@0 1809 bool XMLPrinter::Visit( const XMLComment& comment )
nuclear@0 1810 {
nuclear@0 1811 PushComment( comment.Value() );
nuclear@0 1812 return true;
nuclear@0 1813 }
nuclear@0 1814
nuclear@0 1815 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
nuclear@0 1816 {
nuclear@0 1817 PushDeclaration( declaration.Value() );
nuclear@0 1818 return true;
nuclear@0 1819 }
nuclear@0 1820
nuclear@0 1821
nuclear@0 1822 bool XMLPrinter::Visit( const XMLUnknown& unknown )
nuclear@0 1823 {
nuclear@0 1824 PushUnknown( unknown.Value() );
nuclear@0 1825 return true;
nuclear@0 1826 }