stratgame
diff level/src/tinyxml2.cc @ 0:86b53f76899f
foo
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 21 May 2012 19:07:40 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/level/src/tinyxml2.cc Mon May 21 19:07:40 2012 +0300 1.3 @@ -0,0 +1,1826 @@ 1.4 +/* 1.5 +Original code by Lee Thomason (www.grinninglizard.com) 1.6 + 1.7 +This software is provided 'as-is', without any express or implied 1.8 +warranty. In no event will the authors be held liable for any 1.9 +damages arising from the use of this software. 1.10 + 1.11 +Permission is granted to anyone to use this software for any 1.12 +purpose, including commercial applications, and to alter it and 1.13 +redistribute it freely, subject to the following restrictions: 1.14 + 1.15 +1. The origin of this software must not be misrepresented; you must 1.16 +not claim that you wrote the original software. If you use this 1.17 +software in a product, an acknowledgment in the product documentation 1.18 +would be appreciated but is not required. 1.19 + 1.20 +2. Altered source versions must be plainly marked as such, and 1.21 +must not be misrepresented as being the original software. 1.22 + 1.23 +3. This notice may not be removed or altered from any source 1.24 +distribution. 1.25 +*/ 1.26 + 1.27 +#include "tinyxml2.h" 1.28 + 1.29 +#include <cstdio> 1.30 +#include <cstdlib> 1.31 +#include <new> 1.32 +#include <cstddef> 1.33 + 1.34 +using namespace tinyxml2; 1.35 + 1.36 +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF 1.37 +static const char LF = LINE_FEED; 1.38 +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out 1.39 +static const char CR = CARRIAGE_RETURN; 1.40 +static const char SINGLE_QUOTE = '\''; 1.41 +static const char DOUBLE_QUOTE = '\"'; 1.42 + 1.43 +// Bunch of unicode info at: 1.44 +// http://www.unicode.org/faq/utf_bom.html 1.45 +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 1.46 + 1.47 +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 1.48 +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 1.49 +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 1.50 + 1.51 + 1.52 +#define DELETE_NODE( node ) { \ 1.53 + if ( node ) { \ 1.54 + MemPool* pool = node->memPool; \ 1.55 + node->~XMLNode(); \ 1.56 + pool->Free( node ); \ 1.57 + } \ 1.58 +} 1.59 +#define DELETE_ATTRIBUTE( attrib ) { \ 1.60 + if ( attrib ) { \ 1.61 + MemPool* pool = attrib->memPool; \ 1.62 + attrib->~XMLAttribute(); \ 1.63 + pool->Free( attrib ); \ 1.64 + } \ 1.65 +} 1.66 + 1.67 +struct Entity { 1.68 + const char* pattern; 1.69 + int length; 1.70 + char value; 1.71 +}; 1.72 + 1.73 +static const int NUM_ENTITIES = 5; 1.74 +static const Entity entities[NUM_ENTITIES] = 1.75 +{ 1.76 + { "quot", 4, DOUBLE_QUOTE }, 1.77 + { "amp", 3, '&' }, 1.78 + { "apos", 4, SINGLE_QUOTE }, 1.79 + { "lt", 2, '<' }, 1.80 + { "gt", 2, '>' } 1.81 +}; 1.82 + 1.83 + 1.84 +StrPair::~StrPair() 1.85 +{ 1.86 + Reset(); 1.87 +} 1.88 + 1.89 + 1.90 +void StrPair::Reset() 1.91 +{ 1.92 + if ( flags & NEEDS_DELETE ) { 1.93 + delete [] start; 1.94 + } 1.95 + flags = 0; 1.96 + start = 0; 1.97 + end = 0; 1.98 +} 1.99 + 1.100 + 1.101 +void StrPair::SetStr( const char* str, int flags ) 1.102 +{ 1.103 + Reset(); 1.104 + size_t len = strlen( str ); 1.105 + start = new char[ len+1 ]; 1.106 + memcpy( start, str, len+1 ); 1.107 + end = start + len; 1.108 + this->flags = flags | NEEDS_DELETE; 1.109 +} 1.110 + 1.111 + 1.112 +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) 1.113 +{ 1.114 + TIXMLASSERT( endTag && *endTag ); 1.115 + 1.116 + char* start = p; // fixme: hides a member 1.117 + char endChar = *endTag; 1.118 + size_t length = strlen( endTag ); 1.119 + 1.120 + // Inner loop of text parsing. 1.121 + while ( *p ) { 1.122 + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { 1.123 + Set( start, p, strFlags ); 1.124 + return p + length; 1.125 + } 1.126 + ++p; 1.127 + } 1.128 + return 0; 1.129 +} 1.130 + 1.131 + 1.132 +char* StrPair::ParseName( char* p ) 1.133 +{ 1.134 + char* start = p; 1.135 + 1.136 + if ( !start || !(*start) ) { 1.137 + return 0; 1.138 + } 1.139 + 1.140 + if ( !XMLUtil::IsAlpha( *p ) ) { 1.141 + return 0; 1.142 + } 1.143 + 1.144 + while( *p && ( 1.145 + XMLUtil::IsAlphaNum( (unsigned char) *p ) 1.146 + || *p == '_' 1.147 + || *p == '-' 1.148 + || *p == '.' 1.149 + || *p == ':' )) 1.150 + { 1.151 + ++p; 1.152 + } 1.153 + 1.154 + if ( p > start ) { 1.155 + Set( start, p, 0 ); 1.156 + return p; 1.157 + } 1.158 + return 0; 1.159 +} 1.160 + 1.161 + 1.162 + 1.163 +const char* StrPair::GetStr() 1.164 +{ 1.165 + if ( flags & NEEDS_FLUSH ) { 1.166 + *end = 0; 1.167 + flags ^= NEEDS_FLUSH; 1.168 + 1.169 + if ( flags ) { 1.170 + char* p = start; // the read pointer 1.171 + char* q = start; // the write pointer 1.172 + 1.173 + while( p < end ) { 1.174 + if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { 1.175 + // CR-LF pair becomes LF 1.176 + // CR alone becomes LF 1.177 + // LF-CR becomes LF 1.178 + if ( *(p+1) == LF ) { 1.179 + p += 2; 1.180 + } 1.181 + else { 1.182 + ++p; 1.183 + } 1.184 + *q++ = LF; 1.185 + } 1.186 + else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { 1.187 + if ( *(p+1) == CR ) { 1.188 + p += 2; 1.189 + } 1.190 + else { 1.191 + ++p; 1.192 + } 1.193 + *q++ = LF; 1.194 + } 1.195 + else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { 1.196 + int i=0; 1.197 + 1.198 + // Entities handled by tinyXML2: 1.199 + // - special entities in the entity table [in/out] 1.200 + // - numeric character reference [in] 1.201 + // 中 or 中 1.202 + 1.203 + if ( *(p+1) == '#' ) { 1.204 + char buf[10] = { 0 }; 1.205 + int len; 1.206 + p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); 1.207 + for( int i=0; i<len; ++i ) { 1.208 + *q++ = buf[i]; 1.209 + } 1.210 + TIXMLASSERT( q <= p ); 1.211 + } 1.212 + else { 1.213 + for( i=0; i<NUM_ENTITIES; ++i ) { 1.214 + if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0 1.215 + && *(p+entities[i].length+1) == ';' ) 1.216 + { 1.217 + // Found an entity convert; 1.218 + *q = entities[i].value; 1.219 + ++q; 1.220 + p += entities[i].length + 2; 1.221 + break; 1.222 + } 1.223 + } 1.224 + if ( i == NUM_ENTITIES ) { 1.225 + // fixme: treat as error? 1.226 + ++p; 1.227 + ++q; 1.228 + } 1.229 + } 1.230 + } 1.231 + else { 1.232 + *q = *p; 1.233 + ++p; 1.234 + ++q; 1.235 + } 1.236 + } 1.237 + *q = 0; 1.238 + } 1.239 + flags = (flags & NEEDS_DELETE); 1.240 + } 1.241 + return start; 1.242 +} 1.243 + 1.244 + 1.245 + 1.246 + 1.247 +// --------- XMLUtil ----------- // 1.248 + 1.249 +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) 1.250 +{ 1.251 + *bom = false; 1.252 + const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); 1.253 + // Check for BOM: 1.254 + if ( *(pu+0) == TIXML_UTF_LEAD_0 1.255 + && *(pu+1) == TIXML_UTF_LEAD_1 1.256 + && *(pu+2) == TIXML_UTF_LEAD_2 ) 1.257 + { 1.258 + *bom = true; 1.259 + p += 3; 1.260 + } 1.261 + return p; 1.262 +} 1.263 + 1.264 + 1.265 +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) 1.266 +{ 1.267 + const unsigned long BYTE_MASK = 0xBF; 1.268 + const unsigned long BYTE_MARK = 0x80; 1.269 + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 1.270 + 1.271 + if (input < 0x80) 1.272 + *length = 1; 1.273 + else if ( input < 0x800 ) 1.274 + *length = 2; 1.275 + else if ( input < 0x10000 ) 1.276 + *length = 3; 1.277 + else if ( input < 0x200000 ) 1.278 + *length = 4; 1.279 + else 1.280 + { *length = 0; return; } // This code won't covert this correctly anyway. 1.281 + 1.282 + output += *length; 1.283 + 1.284 + // Scary scary fall throughs. 1.285 + switch (*length) 1.286 + { 1.287 + case 4: 1.288 + --output; 1.289 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 1.290 + input >>= 6; 1.291 + case 3: 1.292 + --output; 1.293 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 1.294 + input >>= 6; 1.295 + case 2: 1.296 + --output; 1.297 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 1.298 + input >>= 6; 1.299 + case 1: 1.300 + --output; 1.301 + *output = (char)(input | FIRST_BYTE_MARK[*length]); 1.302 + } 1.303 +} 1.304 + 1.305 + 1.306 +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) 1.307 +{ 1.308 + // Presume an entity, and pull it out. 1.309 + *length = 0; 1.310 + 1.311 + if ( *(p+1) == '#' && *(p+2) ) 1.312 + { 1.313 + unsigned long ucs = 0; 1.314 + ptrdiff_t delta = 0; 1.315 + unsigned mult = 1; 1.316 + 1.317 + if ( *(p+2) == 'x' ) 1.318 + { 1.319 + // Hexadecimal. 1.320 + if ( !*(p+3) ) return 0; 1.321 + 1.322 + const char* q = p+3; 1.323 + q = strchr( q, ';' ); 1.324 + 1.325 + if ( !q || !*q ) return 0; 1.326 + 1.327 + delta = q-p; 1.328 + --q; 1.329 + 1.330 + while ( *q != 'x' ) 1.331 + { 1.332 + if ( *q >= '0' && *q <= '9' ) 1.333 + ucs += mult * (*q - '0'); 1.334 + else if ( *q >= 'a' && *q <= 'f' ) 1.335 + ucs += mult * (*q - 'a' + 10); 1.336 + else if ( *q >= 'A' && *q <= 'F' ) 1.337 + ucs += mult * (*q - 'A' + 10 ); 1.338 + else 1.339 + return 0; 1.340 + mult *= 16; 1.341 + --q; 1.342 + } 1.343 + } 1.344 + else 1.345 + { 1.346 + // Decimal. 1.347 + if ( !*(p+2) ) return 0; 1.348 + 1.349 + const char* q = p+2; 1.350 + q = strchr( q, ';' ); 1.351 + 1.352 + if ( !q || !*q ) return 0; 1.353 + 1.354 + delta = q-p; 1.355 + --q; 1.356 + 1.357 + while ( *q != '#' ) 1.358 + { 1.359 + if ( *q >= '0' && *q <= '9' ) 1.360 + ucs += mult * (*q - '0'); 1.361 + else 1.362 + return 0; 1.363 + mult *= 10; 1.364 + --q; 1.365 + } 1.366 + } 1.367 + // convert the UCS to UTF-8 1.368 + ConvertUTF32ToUTF8( ucs, value, length ); 1.369 + return p + delta + 1; 1.370 + } 1.371 + return p+1; 1.372 +} 1.373 + 1.374 + 1.375 +char* XMLDocument::Identify( char* p, XMLNode** node ) 1.376 +{ 1.377 + XMLNode* returnNode = 0; 1.378 + char* start = p; 1.379 + p = XMLUtil::SkipWhiteSpace( p ); 1.380 + if( !p || !*p ) 1.381 + { 1.382 + return p; 1.383 + } 1.384 + 1.385 + // What is this thing? 1.386 + // - Elements start with a letter or underscore, but xml is reserved. 1.387 + // - Comments: <!-- 1.388 + // - Decleration: <? 1.389 + // - Everthing else is unknown to tinyxml. 1.390 + // 1.391 + 1.392 + static const char* xmlHeader = { "<?" }; 1.393 + static const char* commentHeader = { "<!--" }; 1.394 + static const char* dtdHeader = { "<!" }; 1.395 + static const char* cdataHeader = { "<![CDATA[" }; 1.396 + static const char* elementHeader = { "<" }; // and a header for everything else; check last. 1.397 + 1.398 + static const int xmlHeaderLen = 2; 1.399 + static const int commentHeaderLen = 4; 1.400 + static const int dtdHeaderLen = 2; 1.401 + static const int cdataHeaderLen = 9; 1.402 + static const int elementHeaderLen = 1; 1.403 + 1.404 +#if defined(_MSC_VER) 1.405 +#pragma warning ( push ) 1.406 +#pragma warning ( disable : 4127 ) 1.407 +#endif 1.408 + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool 1.409 + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool 1.410 +#if defined(_MSC_VER) 1.411 +#pragma warning (pop) 1.412 +#endif 1.413 + if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { 1.414 + returnNode = new (commentPool.Alloc()) XMLDeclaration( this ); 1.415 + returnNode->memPool = &commentPool; 1.416 + p += xmlHeaderLen; 1.417 + } 1.418 + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { 1.419 + returnNode = new (commentPool.Alloc()) XMLComment( this ); 1.420 + returnNode->memPool = &commentPool; 1.421 + p += commentHeaderLen; 1.422 + } 1.423 + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { 1.424 + XMLText* text = new (textPool.Alloc()) XMLText( this ); 1.425 + returnNode = text; 1.426 + returnNode->memPool = &textPool; 1.427 + p += cdataHeaderLen; 1.428 + text->SetCData( true ); 1.429 + } 1.430 + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { 1.431 + returnNode = new (commentPool.Alloc()) XMLUnknown( this ); 1.432 + returnNode->memPool = &commentPool; 1.433 + p += dtdHeaderLen; 1.434 + } 1.435 + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { 1.436 + returnNode = new (elementPool.Alloc()) XMLElement( this ); 1.437 + returnNode->memPool = &elementPool; 1.438 + p += elementHeaderLen; 1.439 + } 1.440 + else { 1.441 + returnNode = new (textPool.Alloc()) XMLText( this ); 1.442 + returnNode->memPool = &textPool; 1.443 + p = start; // Back it up, all the text counts. 1.444 + } 1.445 + 1.446 + *node = returnNode; 1.447 + return p; 1.448 +} 1.449 + 1.450 + 1.451 +bool XMLDocument::Accept( XMLVisitor* visitor ) const 1.452 +{ 1.453 + if ( visitor->VisitEnter( *this ) ) 1.454 + { 1.455 + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) 1.456 + { 1.457 + if ( !node->Accept( visitor ) ) 1.458 + break; 1.459 + } 1.460 + } 1.461 + return visitor->VisitExit( *this ); 1.462 +} 1.463 + 1.464 + 1.465 +// --------- XMLNode ----------- // 1.466 + 1.467 +XMLNode::XMLNode( XMLDocument* doc ) : 1.468 + document( doc ), 1.469 + parent( 0 ), 1.470 + firstChild( 0 ), lastChild( 0 ), 1.471 + prev( 0 ), next( 0 ) 1.472 +{ 1.473 +} 1.474 + 1.475 + 1.476 +XMLNode::~XMLNode() 1.477 +{ 1.478 + DeleteChildren(); 1.479 + if ( parent ) { 1.480 + parent->Unlink( this ); 1.481 + } 1.482 +} 1.483 + 1.484 + 1.485 +void XMLNode::SetValue( const char* str, bool staticMem ) 1.486 +{ 1.487 + if ( staticMem ) 1.488 + value.SetInternedStr( str ); 1.489 + else 1.490 + value.SetStr( str ); 1.491 +} 1.492 + 1.493 + 1.494 +void XMLNode::DeleteChildren() 1.495 +{ 1.496 + while( firstChild ) { 1.497 + XMLNode* node = firstChild; 1.498 + Unlink( node ); 1.499 + 1.500 + DELETE_NODE( node ); 1.501 + } 1.502 + firstChild = lastChild = 0; 1.503 +} 1.504 + 1.505 + 1.506 +void XMLNode::Unlink( XMLNode* child ) 1.507 +{ 1.508 + TIXMLASSERT( child->parent == this ); 1.509 + if ( child == firstChild ) 1.510 + firstChild = firstChild->next; 1.511 + if ( child == lastChild ) 1.512 + lastChild = lastChild->prev; 1.513 + 1.514 + if ( child->prev ) { 1.515 + child->prev->next = child->next; 1.516 + } 1.517 + if ( child->next ) { 1.518 + child->next->prev = child->prev; 1.519 + } 1.520 + child->parent = 0; 1.521 +} 1.522 + 1.523 + 1.524 +void XMLNode::DeleteChild( XMLNode* node ) 1.525 +{ 1.526 + TIXMLASSERT( node->parent == this ); 1.527 + DELETE_NODE( node ); 1.528 +} 1.529 + 1.530 + 1.531 +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) 1.532 +{ 1.533 + if ( lastChild ) { 1.534 + TIXMLASSERT( firstChild ); 1.535 + TIXMLASSERT( lastChild->next == 0 ); 1.536 + lastChild->next = addThis; 1.537 + addThis->prev = lastChild; 1.538 + lastChild = addThis; 1.539 + 1.540 + addThis->next = 0; 1.541 + } 1.542 + else { 1.543 + TIXMLASSERT( firstChild == 0 ); 1.544 + firstChild = lastChild = addThis; 1.545 + 1.546 + addThis->prev = 0; 1.547 + addThis->next = 0; 1.548 + } 1.549 + addThis->parent = this; 1.550 + return addThis; 1.551 +} 1.552 + 1.553 + 1.554 +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) 1.555 +{ 1.556 + if ( firstChild ) { 1.557 + TIXMLASSERT( lastChild ); 1.558 + TIXMLASSERT( firstChild->prev == 0 ); 1.559 + 1.560 + firstChild->prev = addThis; 1.561 + addThis->next = firstChild; 1.562 + firstChild = addThis; 1.563 + 1.564 + addThis->prev = 0; 1.565 + } 1.566 + else { 1.567 + TIXMLASSERT( lastChild == 0 ); 1.568 + firstChild = lastChild = addThis; 1.569 + 1.570 + addThis->prev = 0; 1.571 + addThis->next = 0; 1.572 + } 1.573 + addThis->parent = this; 1.574 + return addThis; 1.575 +} 1.576 + 1.577 + 1.578 +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) 1.579 +{ 1.580 + TIXMLASSERT( afterThis->parent == this ); 1.581 + if ( afterThis->parent != this ) 1.582 + return 0; 1.583 + 1.584 + if ( afterThis->next == 0 ) { 1.585 + // The last node or the only node. 1.586 + return InsertEndChild( addThis ); 1.587 + } 1.588 + addThis->prev = afterThis; 1.589 + addThis->next = afterThis->next; 1.590 + afterThis->next->prev = addThis; 1.591 + afterThis->next = addThis; 1.592 + addThis->parent = this; 1.593 + return addThis; 1.594 +} 1.595 + 1.596 + 1.597 + 1.598 + 1.599 +const XMLElement* XMLNode::FirstChildElement( const char* value ) const 1.600 +{ 1.601 + for( XMLNode* node=firstChild; node; node=node->next ) { 1.602 + XMLElement* element = node->ToElement(); 1.603 + if ( element ) { 1.604 + if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { 1.605 + return element; 1.606 + } 1.607 + } 1.608 + } 1.609 + return 0; 1.610 +} 1.611 + 1.612 + 1.613 +const XMLElement* XMLNode::LastChildElement( const char* value ) const 1.614 +{ 1.615 + for( XMLNode* node=lastChild; node; node=node->prev ) { 1.616 + XMLElement* element = node->ToElement(); 1.617 + if ( element ) { 1.618 + if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { 1.619 + return element; 1.620 + } 1.621 + } 1.622 + } 1.623 + return 0; 1.624 +} 1.625 + 1.626 + 1.627 +const XMLElement* XMLNode::NextSiblingElement( const char* value ) const 1.628 +{ 1.629 + for( XMLNode* element=this->next; element; element = element->next ) { 1.630 + if ( element->ToElement() 1.631 + && (!value || XMLUtil::StringEqual( value, element->Value() ))) 1.632 + { 1.633 + return element->ToElement(); 1.634 + } 1.635 + } 1.636 + return 0; 1.637 +} 1.638 + 1.639 + 1.640 +const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const 1.641 +{ 1.642 + for( XMLNode* element=this->prev; element; element = element->prev ) { 1.643 + if ( element->ToElement() 1.644 + && (!value || XMLUtil::StringEqual( value, element->Value() ))) 1.645 + { 1.646 + return element->ToElement(); 1.647 + } 1.648 + } 1.649 + return 0; 1.650 +} 1.651 + 1.652 + 1.653 +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) 1.654 +{ 1.655 + // This is a recursive method, but thinking about it "at the current level" 1.656 + // it is a pretty simple flat list: 1.657 + // <foo/> 1.658 + // <!-- comment --> 1.659 + // 1.660 + // With a special case: 1.661 + // <foo> 1.662 + // </foo> 1.663 + // <!-- comment --> 1.664 + // 1.665 + // Where the closing element (/foo) *must* be the next thing after the opening 1.666 + // element, and the names must match. BUT the tricky bit is that the closing 1.667 + // element will be read by the child. 1.668 + // 1.669 + // 'endTag' is the end tag for this node, it is returned by a call to a child. 1.670 + // 'parentEnd' is the end tag for the parent, which is filled in and returned. 1.671 + 1.672 + while( p && *p ) { 1.673 + XMLNode* node = 0; 1.674 + 1.675 + p = document->Identify( p, &node ); 1.676 + if ( p == 0 || node == 0 ) { 1.677 + break; 1.678 + } 1.679 + 1.680 + StrPair endTag; 1.681 + p = node->ParseDeep( p, &endTag ); 1.682 + if ( !p ) { 1.683 + DELETE_NODE( node ); 1.684 + node = 0; 1.685 + if ( !document->Error() ) { 1.686 + document->SetError( XML_ERROR_PARSING, 0, 0 ); 1.687 + } 1.688 + break; 1.689 + } 1.690 + 1.691 + // We read the end tag. Return it to the parent. 1.692 + if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) { 1.693 + if ( parentEnd ) { 1.694 + *parentEnd = ((XMLElement*)node)->value; 1.695 + } 1.696 + DELETE_NODE( node ); 1.697 + return p; 1.698 + } 1.699 + 1.700 + // Handle an end tag returned to this level. 1.701 + // And handle a bunch of annoying errors. 1.702 + XMLElement* ele = node->ToElement(); 1.703 + if ( ele ) { 1.704 + if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) { 1.705 + document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 1.706 + p = 0; 1.707 + } 1.708 + else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) { 1.709 + document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 1.710 + p = 0; 1.711 + } 1.712 + else if ( !endTag.Empty() ) { 1.713 + if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { 1.714 + document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 1.715 + p = 0; 1.716 + } 1.717 + } 1.718 + } 1.719 + if ( p == 0 ) { 1.720 + DELETE_NODE( node ); 1.721 + node = 0; 1.722 + } 1.723 + if ( node ) { 1.724 + this->InsertEndChild( node ); 1.725 + } 1.726 + } 1.727 + return 0; 1.728 +} 1.729 + 1.730 +// --------- XMLText ---------- // 1.731 +char* XMLText::ParseDeep( char* p, StrPair* ) 1.732 +{ 1.733 + const char* start = p; 1.734 + if ( this->CData() ) { 1.735 + p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 1.736 + if ( !p ) { 1.737 + document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); 1.738 + } 1.739 + return p; 1.740 + } 1.741 + else { 1.742 + p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES ); 1.743 + if ( !p ) { 1.744 + document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); 1.745 + } 1.746 + if ( p && *p ) { 1.747 + return p-1; 1.748 + } 1.749 + } 1.750 + return 0; 1.751 +} 1.752 + 1.753 + 1.754 +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const 1.755 +{ 1.756 + if ( !doc ) { 1.757 + doc = document; 1.758 + } 1.759 + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? 1.760 + text->SetCData( this->CData() ); 1.761 + return text; 1.762 +} 1.763 + 1.764 + 1.765 +bool XMLText::ShallowEqual( const XMLNode* compare ) const 1.766 +{ 1.767 + return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() )); 1.768 +} 1.769 + 1.770 + 1.771 +bool XMLText::Accept( XMLVisitor* visitor ) const 1.772 +{ 1.773 + return visitor->Visit( *this ); 1.774 +} 1.775 + 1.776 + 1.777 +// --------- XMLComment ---------- // 1.778 + 1.779 +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) 1.780 +{ 1.781 +} 1.782 + 1.783 + 1.784 +XMLComment::~XMLComment() 1.785 +{ 1.786 + //printf( "~XMLComment\n" ); 1.787 +} 1.788 + 1.789 + 1.790 +char* XMLComment::ParseDeep( char* p, StrPair* ) 1.791 +{ 1.792 + // Comment parses as text. 1.793 + const char* start = p; 1.794 + p = value.ParseText( p, "-->", StrPair::COMMENT ); 1.795 + if ( p == 0 ) { 1.796 + document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); 1.797 + } 1.798 + return p; 1.799 +} 1.800 + 1.801 + 1.802 +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const 1.803 +{ 1.804 + if ( !doc ) { 1.805 + doc = document; 1.806 + } 1.807 + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? 1.808 + return comment; 1.809 +} 1.810 + 1.811 + 1.812 +bool XMLComment::ShallowEqual( const XMLNode* compare ) const 1.813 +{ 1.814 + return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() )); 1.815 +} 1.816 + 1.817 + 1.818 +bool XMLComment::Accept( XMLVisitor* visitor ) const 1.819 +{ 1.820 + return visitor->Visit( *this ); 1.821 +} 1.822 + 1.823 + 1.824 +// --------- XMLDeclaration ---------- // 1.825 + 1.826 +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) 1.827 +{ 1.828 +} 1.829 + 1.830 + 1.831 +XMLDeclaration::~XMLDeclaration() 1.832 +{ 1.833 + //printf( "~XMLDeclaration\n" ); 1.834 +} 1.835 + 1.836 + 1.837 +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) 1.838 +{ 1.839 + // Declaration parses as text. 1.840 + const char* start = p; 1.841 + p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 1.842 + if ( p == 0 ) { 1.843 + document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); 1.844 + } 1.845 + return p; 1.846 +} 1.847 + 1.848 + 1.849 +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const 1.850 +{ 1.851 + if ( !doc ) { 1.852 + doc = document; 1.853 + } 1.854 + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? 1.855 + return dec; 1.856 +} 1.857 + 1.858 + 1.859 +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const 1.860 +{ 1.861 + return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() )); 1.862 +} 1.863 + 1.864 + 1.865 + 1.866 +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const 1.867 +{ 1.868 + return visitor->Visit( *this ); 1.869 +} 1.870 + 1.871 +// --------- XMLUnknown ---------- // 1.872 + 1.873 +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) 1.874 +{ 1.875 +} 1.876 + 1.877 + 1.878 +XMLUnknown::~XMLUnknown() 1.879 +{ 1.880 +} 1.881 + 1.882 + 1.883 +char* XMLUnknown::ParseDeep( char* p, StrPair* ) 1.884 +{ 1.885 + // Unknown parses as text. 1.886 + const char* start = p; 1.887 + 1.888 + p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 1.889 + if ( !p ) { 1.890 + document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); 1.891 + } 1.892 + return p; 1.893 +} 1.894 + 1.895 + 1.896 +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const 1.897 +{ 1.898 + if ( !doc ) { 1.899 + doc = document; 1.900 + } 1.901 + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? 1.902 + return text; 1.903 +} 1.904 + 1.905 + 1.906 +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const 1.907 +{ 1.908 + return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() )); 1.909 +} 1.910 + 1.911 + 1.912 +bool XMLUnknown::Accept( XMLVisitor* visitor ) const 1.913 +{ 1.914 + return visitor->Visit( *this ); 1.915 +} 1.916 + 1.917 +// --------- XMLAttribute ---------- // 1.918 +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) 1.919 +{ 1.920 + p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME ); 1.921 + if ( !p || !*p ) return 0; 1.922 + 1.923 + char endTag[2] = { *p, 0 }; 1.924 + ++p; 1.925 + p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); 1.926 + //if ( value.Empty() ) return 0; 1.927 + return p; 1.928 +} 1.929 + 1.930 + 1.931 +void XMLAttribute::SetName( const char* n ) 1.932 +{ 1.933 + name.SetStr( n ); 1.934 +} 1.935 + 1.936 + 1.937 +int XMLAttribute::QueryIntValue( int* value ) const 1.938 +{ 1.939 + if ( TIXML_SSCANF( Value(), "%d", value ) == 1 ) 1.940 + return XML_NO_ERROR; 1.941 + return XML_WRONG_ATTRIBUTE_TYPE; 1.942 +} 1.943 + 1.944 + 1.945 +int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const 1.946 +{ 1.947 + if ( TIXML_SSCANF( Value(), "%u", value ) == 1 ) 1.948 + return XML_NO_ERROR; 1.949 + return XML_WRONG_ATTRIBUTE_TYPE; 1.950 +} 1.951 + 1.952 + 1.953 +int XMLAttribute::QueryBoolValue( bool* value ) const 1.954 +{ 1.955 + int ival = -1; 1.956 + QueryIntValue( &ival ); 1.957 + 1.958 + if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) { 1.959 + *value = true; 1.960 + return XML_NO_ERROR; 1.961 + } 1.962 + else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) { 1.963 + *value = false; 1.964 + return XML_NO_ERROR; 1.965 + } 1.966 + return XML_WRONG_ATTRIBUTE_TYPE; 1.967 +} 1.968 + 1.969 + 1.970 +int XMLAttribute::QueryDoubleValue( double* value ) const 1.971 +{ 1.972 + if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 ) 1.973 + return XML_NO_ERROR; 1.974 + return XML_WRONG_ATTRIBUTE_TYPE; 1.975 +} 1.976 + 1.977 + 1.978 +int XMLAttribute::QueryFloatValue( float* value ) const 1.979 +{ 1.980 + if ( TIXML_SSCANF( Value(), "%f", value ) == 1 ) 1.981 + return XML_NO_ERROR; 1.982 + return XML_WRONG_ATTRIBUTE_TYPE; 1.983 +} 1.984 + 1.985 + 1.986 +void XMLAttribute::SetAttribute( const char* v ) 1.987 +{ 1.988 + value.SetStr( v ); 1.989 +} 1.990 + 1.991 + 1.992 +void XMLAttribute::SetAttribute( int v ) 1.993 +{ 1.994 + char buf[BUF_SIZE]; 1.995 + TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ); 1.996 + value.SetStr( buf ); 1.997 +} 1.998 + 1.999 + 1.1000 +void XMLAttribute::SetAttribute( unsigned v ) 1.1001 +{ 1.1002 + char buf[BUF_SIZE]; 1.1003 + TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v ); 1.1004 + value.SetStr( buf ); 1.1005 +} 1.1006 + 1.1007 + 1.1008 +void XMLAttribute::SetAttribute( bool v ) 1.1009 +{ 1.1010 + char buf[BUF_SIZE]; 1.1011 + TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 ); 1.1012 + value.SetStr( buf ); 1.1013 +} 1.1014 + 1.1015 +void XMLAttribute::SetAttribute( double v ) 1.1016 +{ 1.1017 + char buf[BUF_SIZE]; 1.1018 + TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v ); 1.1019 + value.SetStr( buf ); 1.1020 +} 1.1021 + 1.1022 +void XMLAttribute::SetAttribute( float v ) 1.1023 +{ 1.1024 + char buf[BUF_SIZE]; 1.1025 + TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v ); 1.1026 + value.SetStr( buf ); 1.1027 +} 1.1028 + 1.1029 + 1.1030 +// --------- XMLElement ---------- // 1.1031 +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), 1.1032 + closingType( 0 ), 1.1033 + rootAttribute( 0 ) 1.1034 +{ 1.1035 +} 1.1036 + 1.1037 + 1.1038 +XMLElement::~XMLElement() 1.1039 +{ 1.1040 + while( rootAttribute ) { 1.1041 + XMLAttribute* next = rootAttribute->next; 1.1042 + DELETE_ATTRIBUTE( rootAttribute ); 1.1043 + rootAttribute = next; 1.1044 + } 1.1045 +} 1.1046 + 1.1047 + 1.1048 +XMLAttribute* XMLElement::FindAttribute( const char* name ) 1.1049 +{ 1.1050 + XMLAttribute* a = 0; 1.1051 + for( a=rootAttribute; a; a = a->next ) { 1.1052 + if ( XMLUtil::StringEqual( a->Name(), name ) ) 1.1053 + return a; 1.1054 + } 1.1055 + return 0; 1.1056 +} 1.1057 + 1.1058 + 1.1059 +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const 1.1060 +{ 1.1061 + XMLAttribute* a = 0; 1.1062 + for( a=rootAttribute; a; a = a->next ) { 1.1063 + if ( XMLUtil::StringEqual( a->Name(), name ) ) 1.1064 + return a; 1.1065 + } 1.1066 + return 0; 1.1067 +} 1.1068 + 1.1069 + 1.1070 +const char* XMLElement::Attribute( const char* name, const char* value ) const 1.1071 +{ 1.1072 + const XMLAttribute* a = FindAttribute( name ); 1.1073 + if ( !a ) 1.1074 + return 0; 1.1075 + if ( !value || XMLUtil::StringEqual( a->Value(), value )) 1.1076 + return a->Value(); 1.1077 + return 0; 1.1078 +} 1.1079 + 1.1080 + 1.1081 +const char* XMLElement::GetText() const 1.1082 +{ 1.1083 + if ( FirstChild() && FirstChild()->ToText() ) { 1.1084 + return FirstChild()->ToText()->Value(); 1.1085 + } 1.1086 + return 0; 1.1087 +} 1.1088 + 1.1089 + 1.1090 +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) 1.1091 +{ 1.1092 + XMLAttribute* last = 0; 1.1093 + XMLAttribute* attrib = 0; 1.1094 + for( attrib = rootAttribute; 1.1095 + attrib; 1.1096 + last = attrib, attrib = attrib->next ) 1.1097 + { 1.1098 + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { 1.1099 + break; 1.1100 + } 1.1101 + } 1.1102 + if ( !attrib ) { 1.1103 + attrib = new (document->attributePool.Alloc() ) XMLAttribute(); 1.1104 + attrib->memPool = &document->attributePool; 1.1105 + if ( last ) { 1.1106 + last->next = attrib; 1.1107 + } 1.1108 + else { 1.1109 + rootAttribute = attrib; 1.1110 + } 1.1111 + attrib->SetName( name ); 1.1112 + } 1.1113 + return attrib; 1.1114 +} 1.1115 + 1.1116 + 1.1117 +void XMLElement::DeleteAttribute( const char* name ) 1.1118 +{ 1.1119 + XMLAttribute* prev = 0; 1.1120 + for( XMLAttribute* a=rootAttribute; a; a=a->next ) { 1.1121 + if ( XMLUtil::StringEqual( name, a->Name() ) ) { 1.1122 + if ( prev ) { 1.1123 + prev->next = a->next; 1.1124 + } 1.1125 + else { 1.1126 + rootAttribute = a->next; 1.1127 + } 1.1128 + DELETE_ATTRIBUTE( a ); 1.1129 + break; 1.1130 + } 1.1131 + prev = a; 1.1132 + } 1.1133 +} 1.1134 + 1.1135 + 1.1136 +char* XMLElement::ParseAttributes( char* p ) 1.1137 +{ 1.1138 + const char* start = p; 1.1139 + XMLAttribute* prevAttribute = 0; 1.1140 + 1.1141 + // Read the attributes. 1.1142 + while( p ) { 1.1143 + p = XMLUtil::SkipWhiteSpace( p ); 1.1144 + if ( !p || !(*p) ) { 1.1145 + document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); 1.1146 + return 0; 1.1147 + } 1.1148 + 1.1149 + // attribute. 1.1150 + if ( XMLUtil::IsAlpha( *p ) ) { 1.1151 + XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute(); 1.1152 + attrib->memPool = &document->attributePool; 1.1153 + 1.1154 + p = attrib->ParseDeep( p, document->ProcessEntities() ); 1.1155 + if ( !p || Attribute( attrib->Name() ) ) { 1.1156 + DELETE_ATTRIBUTE( attrib ); 1.1157 + document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); 1.1158 + return 0; 1.1159 + } 1.1160 + // There is a minor bug here: if the attribute in the source xml 1.1161 + // document is duplicated, it will not be detected and the 1.1162 + // attribute will be doubly added. However, tracking the 'prevAttribute' 1.1163 + // avoids re-scanning the attribute list. Preferring performance for 1.1164 + // now, may reconsider in the future. 1.1165 + if ( prevAttribute ) { 1.1166 + prevAttribute->next = attrib; 1.1167 + } 1.1168 + else { 1.1169 + rootAttribute = attrib; 1.1170 + } 1.1171 + prevAttribute = attrib; 1.1172 + } 1.1173 + // end of the tag 1.1174 + else if ( *p == '/' && *(p+1) == '>' ) { 1.1175 + closingType = CLOSED; 1.1176 + return p+2; // done; sealed element. 1.1177 + } 1.1178 + // end of the tag 1.1179 + else if ( *p == '>' ) { 1.1180 + ++p; 1.1181 + break; 1.1182 + } 1.1183 + else { 1.1184 + document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); 1.1185 + return 0; 1.1186 + } 1.1187 + } 1.1188 + return p; 1.1189 +} 1.1190 + 1.1191 + 1.1192 +// 1.1193 +// <ele></ele> 1.1194 +// <ele>foo<b>bar</b></ele> 1.1195 +// 1.1196 +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) 1.1197 +{ 1.1198 + // Read the element name. 1.1199 + p = XMLUtil::SkipWhiteSpace( p ); 1.1200 + if ( !p ) return 0; 1.1201 + 1.1202 + // The closing element is the </element> form. It is 1.1203 + // parsed just like a regular element then deleted from 1.1204 + // the DOM. 1.1205 + if ( *p == '/' ) { 1.1206 + closingType = CLOSING; 1.1207 + ++p; 1.1208 + } 1.1209 + 1.1210 + p = value.ParseName( p ); 1.1211 + if ( value.Empty() ) return 0; 1.1212 + 1.1213 + p = ParseAttributes( p ); 1.1214 + if ( !p || !*p || closingType ) 1.1215 + return p; 1.1216 + 1.1217 + p = XMLNode::ParseDeep( p, strPair ); 1.1218 + return p; 1.1219 +} 1.1220 + 1.1221 + 1.1222 + 1.1223 +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const 1.1224 +{ 1.1225 + if ( !doc ) { 1.1226 + doc = document; 1.1227 + } 1.1228 + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? 1.1229 + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { 1.1230 + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? 1.1231 + } 1.1232 + return element; 1.1233 +} 1.1234 + 1.1235 + 1.1236 +bool XMLElement::ShallowEqual( const XMLNode* compare ) const 1.1237 +{ 1.1238 + const XMLElement* other = compare->ToElement(); 1.1239 + if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { 1.1240 + 1.1241 + const XMLAttribute* a=FirstAttribute(); 1.1242 + const XMLAttribute* b=other->FirstAttribute(); 1.1243 + 1.1244 + while ( a && b ) { 1.1245 + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { 1.1246 + return false; 1.1247 + } 1.1248 + } 1.1249 + if ( a || b ) { 1.1250 + // different count 1.1251 + return false; 1.1252 + } 1.1253 + return true; 1.1254 + } 1.1255 + return false; 1.1256 +} 1.1257 + 1.1258 + 1.1259 +bool XMLElement::Accept( XMLVisitor* visitor ) const 1.1260 +{ 1.1261 + if ( visitor->VisitEnter( *this, rootAttribute ) ) 1.1262 + { 1.1263 + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) 1.1264 + { 1.1265 + if ( !node->Accept( visitor ) ) 1.1266 + break; 1.1267 + } 1.1268 + } 1.1269 + return visitor->VisitExit( *this ); 1.1270 +} 1.1271 + 1.1272 + 1.1273 +// --------- XMLDocument ----------- // 1.1274 +XMLDocument::XMLDocument( bool _processEntities ) : 1.1275 + XMLNode( 0 ), 1.1276 + writeBOM( false ), 1.1277 + processEntities( _processEntities ), 1.1278 + errorID( 0 ), 1.1279 + errorStr1( 0 ), 1.1280 + errorStr2( 0 ), 1.1281 + charBuffer( 0 ) 1.1282 +{ 1.1283 + document = this; // avoid warning about 'this' in initializer list 1.1284 +} 1.1285 + 1.1286 + 1.1287 +XMLDocument::~XMLDocument() 1.1288 +{ 1.1289 + DeleteChildren(); 1.1290 + delete [] charBuffer; 1.1291 + 1.1292 +#if 0 1.1293 + textPool.Trace( "text" ); 1.1294 + elementPool.Trace( "element" ); 1.1295 + commentPool.Trace( "comment" ); 1.1296 + attributePool.Trace( "attribute" ); 1.1297 +#endif 1.1298 + 1.1299 + TIXMLASSERT( textPool.CurrentAllocs() == 0 ); 1.1300 + TIXMLASSERT( elementPool.CurrentAllocs() == 0 ); 1.1301 + TIXMLASSERT( commentPool.CurrentAllocs() == 0 ); 1.1302 + TIXMLASSERT( attributePool.CurrentAllocs() == 0 ); 1.1303 +} 1.1304 + 1.1305 + 1.1306 +void XMLDocument::InitDocument() 1.1307 +{ 1.1308 + errorID = XML_NO_ERROR; 1.1309 + errorStr1 = 0; 1.1310 + errorStr2 = 0; 1.1311 + 1.1312 + delete [] charBuffer; 1.1313 + charBuffer = 0; 1.1314 + 1.1315 +} 1.1316 + 1.1317 + 1.1318 +XMLElement* XMLDocument::NewElement( const char* name ) 1.1319 +{ 1.1320 + XMLElement* ele = new (elementPool.Alloc()) XMLElement( this ); 1.1321 + ele->memPool = &elementPool; 1.1322 + ele->SetName( name ); 1.1323 + return ele; 1.1324 +} 1.1325 + 1.1326 + 1.1327 +XMLComment* XMLDocument::NewComment( const char* str ) 1.1328 +{ 1.1329 + XMLComment* comment = new (commentPool.Alloc()) XMLComment( this ); 1.1330 + comment->memPool = &commentPool; 1.1331 + comment->SetValue( str ); 1.1332 + return comment; 1.1333 +} 1.1334 + 1.1335 + 1.1336 +XMLText* XMLDocument::NewText( const char* str ) 1.1337 +{ 1.1338 + XMLText* text = new (textPool.Alloc()) XMLText( this ); 1.1339 + text->memPool = &textPool; 1.1340 + text->SetValue( str ); 1.1341 + return text; 1.1342 +} 1.1343 + 1.1344 + 1.1345 +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) 1.1346 +{ 1.1347 + XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this ); 1.1348 + dec->memPool = &commentPool; 1.1349 + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); 1.1350 + return dec; 1.1351 +} 1.1352 + 1.1353 + 1.1354 +XMLUnknown* XMLDocument::NewUnknown( const char* str ) 1.1355 +{ 1.1356 + XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this ); 1.1357 + unk->memPool = &commentPool; 1.1358 + unk->SetValue( str ); 1.1359 + return unk; 1.1360 +} 1.1361 + 1.1362 + 1.1363 +int XMLDocument::LoadFile( const char* filename ) 1.1364 +{ 1.1365 + DeleteChildren(); 1.1366 + InitDocument(); 1.1367 + 1.1368 +#if defined(_MSC_VER) 1.1369 +#pragma warning ( push ) 1.1370 +#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. 1.1371 +#endif 1.1372 + FILE* fp = fopen( filename, "rb" ); 1.1373 +#if defined(_MSC_VER) 1.1374 +#pragma warning ( pop ) 1.1375 +#endif 1.1376 + if ( !fp ) { 1.1377 + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); 1.1378 + return errorID; 1.1379 + } 1.1380 + LoadFile( fp ); 1.1381 + fclose( fp ); 1.1382 + return errorID; 1.1383 +} 1.1384 + 1.1385 + 1.1386 +int XMLDocument::LoadFile( FILE* fp ) 1.1387 +{ 1.1388 + DeleteChildren(); 1.1389 + InitDocument(); 1.1390 + 1.1391 + fseek( fp, 0, SEEK_END ); 1.1392 + unsigned size = ftell( fp ); 1.1393 + fseek( fp, 0, SEEK_SET ); 1.1394 + 1.1395 + if ( size == 0 ) { 1.1396 + return errorID; 1.1397 + } 1.1398 + 1.1399 + charBuffer = new char[size+1]; 1.1400 + fread( charBuffer, size, 1, fp ); 1.1401 + charBuffer[size] = 0; 1.1402 + 1.1403 + const char* p = charBuffer; 1.1404 + p = XMLUtil::SkipWhiteSpace( p ); 1.1405 + p = XMLUtil::ReadBOM( p, &writeBOM ); 1.1406 + if ( !p || !*p ) { 1.1407 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 1.1408 + return errorID; 1.1409 + } 1.1410 + 1.1411 + ParseDeep( charBuffer + (p-charBuffer), 0 ); 1.1412 + return errorID; 1.1413 +} 1.1414 + 1.1415 + 1.1416 +int XMLDocument::SaveFile( const char* filename ) 1.1417 +{ 1.1418 +#if defined(_MSC_VER) 1.1419 +#pragma warning ( push ) 1.1420 +#pragma warning ( disable : 4996 ) // Fail to see a compelling reason why this should be deprecated. 1.1421 +#endif 1.1422 + FILE* fp = fopen( filename, "w" ); 1.1423 +#if defined(_MSC_VER) 1.1424 +#pragma warning ( pop ) 1.1425 +#endif 1.1426 + if ( !fp ) { 1.1427 + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); 1.1428 + return errorID; 1.1429 + } 1.1430 + SaveFile(fp); 1.1431 + fclose( fp ); 1.1432 + return errorID; 1.1433 +} 1.1434 + 1.1435 + 1.1436 +int XMLDocument::SaveFile( FILE* fp ) 1.1437 +{ 1.1438 + XMLPrinter stream( fp ); 1.1439 + Print( &stream ); 1.1440 + return errorID; 1.1441 +} 1.1442 + 1.1443 + 1.1444 +int XMLDocument::Parse( const char* p ) 1.1445 +{ 1.1446 + DeleteChildren(); 1.1447 + InitDocument(); 1.1448 + 1.1449 + if ( !p || !*p ) { 1.1450 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 1.1451 + return errorID; 1.1452 + } 1.1453 + p = XMLUtil::SkipWhiteSpace( p ); 1.1454 + p = XMLUtil::ReadBOM( p, &writeBOM ); 1.1455 + if ( !p || !*p ) { 1.1456 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 1.1457 + return errorID; 1.1458 + } 1.1459 + 1.1460 + size_t len = strlen( p ); 1.1461 + charBuffer = new char[ len+1 ]; 1.1462 + memcpy( charBuffer, p, len+1 ); 1.1463 + 1.1464 + 1.1465 + ParseDeep( charBuffer, 0 ); 1.1466 + return errorID; 1.1467 +} 1.1468 + 1.1469 + 1.1470 +void XMLDocument::Print( XMLPrinter* streamer ) 1.1471 +{ 1.1472 + XMLPrinter stdStreamer( stdout ); 1.1473 + if ( !streamer ) 1.1474 + streamer = &stdStreamer; 1.1475 + Accept( streamer ); 1.1476 +} 1.1477 + 1.1478 + 1.1479 +void XMLDocument::SetError( int error, const char* str1, const char* str2 ) 1.1480 +{ 1.1481 + errorID = error; 1.1482 + errorStr1 = str1; 1.1483 + errorStr2 = str2; 1.1484 +} 1.1485 + 1.1486 + 1.1487 +void XMLDocument::PrintError() const 1.1488 +{ 1.1489 + if ( errorID ) { 1.1490 + static const int LEN = 20; 1.1491 + char buf1[LEN] = { 0 }; 1.1492 + char buf2[LEN] = { 0 }; 1.1493 + 1.1494 + if ( errorStr1 ) { 1.1495 + TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 ); 1.1496 + } 1.1497 + if ( errorStr2 ) { 1.1498 + TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 ); 1.1499 + } 1.1500 + 1.1501 + printf( "XMLDocument error id=%d str1=%s str2=%s\n", 1.1502 + errorID, buf1, buf2 ); 1.1503 + } 1.1504 +} 1.1505 + 1.1506 + 1.1507 +XMLPrinter::XMLPrinter( FILE* file ) : 1.1508 + elementJustOpened( false ), 1.1509 + firstElement( true ), 1.1510 + fp( file ), 1.1511 + depth( 0 ), 1.1512 + textDepth( -1 ), 1.1513 + processEntities( true ) 1.1514 +{ 1.1515 + for( int i=0; i<ENTITY_RANGE; ++i ) { 1.1516 + entityFlag[i] = false; 1.1517 + restrictedEntityFlag[i] = false; 1.1518 + } 1.1519 + for( int i=0; i<NUM_ENTITIES; ++i ) { 1.1520 + TIXMLASSERT( entities[i].value < ENTITY_RANGE ); 1.1521 + if ( entities[i].value < ENTITY_RANGE ) { 1.1522 + entityFlag[ (int)entities[i].value ] = true; 1.1523 + } 1.1524 + } 1.1525 + restrictedEntityFlag[(int)'&'] = true; 1.1526 + restrictedEntityFlag[(int)'<'] = true; 1.1527 + restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice 1.1528 + buffer.Push( 0 ); 1.1529 +} 1.1530 + 1.1531 + 1.1532 +void XMLPrinter::Print( const char* format, ... ) 1.1533 +{ 1.1534 + va_list va; 1.1535 + va_start( va, format ); 1.1536 + 1.1537 + if ( fp ) { 1.1538 + vfprintf( fp, format, va ); 1.1539 + } 1.1540 + else { 1.1541 + // This seems brutally complex. Haven't figured out a better 1.1542 + // way on windows. 1.1543 + #ifdef _MSC_VER 1.1544 + int len = -1; 1.1545 + int expand = 1000; 1.1546 + while ( len < 0 ) { 1.1547 + len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va ); 1.1548 + if ( len < 0 ) { 1.1549 + expand *= 3/2; 1.1550 + accumulator.PushArr( expand ); 1.1551 + } 1.1552 + } 1.1553 + char* p = buffer.PushArr( len ) - 1; 1.1554 + memcpy( p, accumulator.Mem(), len+1 ); 1.1555 + #else 1.1556 + int len = vsnprintf( 0, 0, format, va ); 1.1557 + // Close out and re-start the va-args 1.1558 + va_end( va ); 1.1559 + va_start( va, format ); 1.1560 + char* p = buffer.PushArr( len ) - 1; 1.1561 + vsnprintf( p, len+1, format, va ); 1.1562 + #endif 1.1563 + } 1.1564 + va_end( va ); 1.1565 +} 1.1566 + 1.1567 + 1.1568 +void XMLPrinter::PrintSpace( int depth ) 1.1569 +{ 1.1570 + for( int i=0; i<depth; ++i ) { 1.1571 + Print( " " ); 1.1572 + } 1.1573 +} 1.1574 + 1.1575 + 1.1576 +void XMLPrinter::PrintString( const char* p, bool restricted ) 1.1577 +{ 1.1578 + // Look for runs of bytes between entities to print. 1.1579 + const char* q = p; 1.1580 + const bool* flag = restricted ? restrictedEntityFlag : entityFlag; 1.1581 + 1.1582 + if ( processEntities ) { 1.1583 + while ( *q ) { 1.1584 + // Remember, char is sometimes signed. (How many times has that bitten me?) 1.1585 + if ( *q > 0 && *q < ENTITY_RANGE ) { 1.1586 + // Check for entities. If one is found, flush 1.1587 + // the stream up until the entity, write the 1.1588 + // entity, and keep looking. 1.1589 + if ( flag[(unsigned)(*q)] ) { 1.1590 + while ( p < q ) { 1.1591 + Print( "%c", *p ); 1.1592 + ++p; 1.1593 + } 1.1594 + for( int i=0; i<NUM_ENTITIES; ++i ) { 1.1595 + if ( entities[i].value == *q ) { 1.1596 + Print( "&%s;", entities[i].pattern ); 1.1597 + break; 1.1598 + } 1.1599 + } 1.1600 + ++p; 1.1601 + } 1.1602 + } 1.1603 + ++q; 1.1604 + } 1.1605 + } 1.1606 + // Flush the remaining string. This will be the entire 1.1607 + // string if an entity wasn't found. 1.1608 + if ( !processEntities || (q-p > 0) ) { 1.1609 + Print( "%s", p ); 1.1610 + } 1.1611 +} 1.1612 + 1.1613 + 1.1614 +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) 1.1615 +{ 1.1616 + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; 1.1617 + if ( writeBOM ) { 1.1618 + Print( "%s", bom ); 1.1619 + } 1.1620 + if ( writeDec ) { 1.1621 + PushDeclaration( "xml version=\"1.0\"" ); 1.1622 + } 1.1623 +} 1.1624 + 1.1625 + 1.1626 +void XMLPrinter::OpenElement( const char* name ) 1.1627 +{ 1.1628 + if ( elementJustOpened ) { 1.1629 + SealElement(); 1.1630 + } 1.1631 + stack.Push( name ); 1.1632 + 1.1633 + if ( textDepth < 0 && !firstElement ) { 1.1634 + Print( "\n" ); 1.1635 + PrintSpace( depth ); 1.1636 + } 1.1637 + 1.1638 + Print( "<%s", name ); 1.1639 + elementJustOpened = true; 1.1640 + firstElement = false; 1.1641 + ++depth; 1.1642 +} 1.1643 + 1.1644 + 1.1645 +void XMLPrinter::PushAttribute( const char* name, const char* value ) 1.1646 +{ 1.1647 + TIXMLASSERT( elementJustOpened ); 1.1648 + Print( " %s=\"", name ); 1.1649 + PrintString( value, false ); 1.1650 + Print( "\"" ); 1.1651 +} 1.1652 + 1.1653 + 1.1654 +void XMLPrinter::PushAttribute( const char* name, int v ) 1.1655 +{ 1.1656 + char buf[BUF_SIZE]; 1.1657 + TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ); 1.1658 + PushAttribute( name, buf ); 1.1659 +} 1.1660 + 1.1661 + 1.1662 +void XMLPrinter::PushAttribute( const char* name, unsigned v ) 1.1663 +{ 1.1664 + char buf[BUF_SIZE]; 1.1665 + TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v ); 1.1666 + PushAttribute( name, buf ); 1.1667 +} 1.1668 + 1.1669 + 1.1670 +void XMLPrinter::PushAttribute( const char* name, bool v ) 1.1671 +{ 1.1672 + char buf[BUF_SIZE]; 1.1673 + TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 ); 1.1674 + PushAttribute( name, buf ); 1.1675 +} 1.1676 + 1.1677 + 1.1678 +void XMLPrinter::PushAttribute( const char* name, double v ) 1.1679 +{ 1.1680 + char buf[BUF_SIZE]; 1.1681 + TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v ); 1.1682 + PushAttribute( name, buf ); 1.1683 +} 1.1684 + 1.1685 + 1.1686 +void XMLPrinter::CloseElement() 1.1687 +{ 1.1688 + --depth; 1.1689 + const char* name = stack.Pop(); 1.1690 + 1.1691 + if ( elementJustOpened ) { 1.1692 + Print( "/>" ); 1.1693 + } 1.1694 + else { 1.1695 + if ( textDepth < 0 ) { 1.1696 + Print( "\n" ); 1.1697 + PrintSpace( depth ); 1.1698 + } 1.1699 + Print( "</%s>", name ); 1.1700 + } 1.1701 + 1.1702 + if ( textDepth == depth ) 1.1703 + textDepth = -1; 1.1704 + if ( depth == 0 ) 1.1705 + Print( "\n" ); 1.1706 + elementJustOpened = false; 1.1707 +} 1.1708 + 1.1709 + 1.1710 +void XMLPrinter::SealElement() 1.1711 +{ 1.1712 + elementJustOpened = false; 1.1713 + Print( ">" ); 1.1714 +} 1.1715 + 1.1716 + 1.1717 +void XMLPrinter::PushText( const char* text, bool cdata ) 1.1718 +{ 1.1719 + textDepth = depth-1; 1.1720 + 1.1721 + if ( elementJustOpened ) { 1.1722 + SealElement(); 1.1723 + } 1.1724 + if ( cdata ) { 1.1725 + Print( "<![CDATA[" ); 1.1726 + Print( "%s", text ); 1.1727 + Print( "]]>" ); 1.1728 + } 1.1729 + else { 1.1730 + PrintString( text, true ); 1.1731 + } 1.1732 +} 1.1733 + 1.1734 + 1.1735 +void XMLPrinter::PushComment( const char* comment ) 1.1736 +{ 1.1737 + if ( elementJustOpened ) { 1.1738 + SealElement(); 1.1739 + } 1.1740 + if ( textDepth < 0 && !firstElement ) { 1.1741 + Print( "\n" ); 1.1742 + PrintSpace( depth ); 1.1743 + } 1.1744 + firstElement = false; 1.1745 + Print( "<!--%s-->", comment ); 1.1746 +} 1.1747 + 1.1748 + 1.1749 +void XMLPrinter::PushDeclaration( const char* value ) 1.1750 +{ 1.1751 + if ( elementJustOpened ) { 1.1752 + SealElement(); 1.1753 + } 1.1754 + if ( textDepth < 0 && !firstElement) { 1.1755 + Print( "\n" ); 1.1756 + PrintSpace( depth ); 1.1757 + } 1.1758 + firstElement = false; 1.1759 + Print( "<?%s?>", value ); 1.1760 +} 1.1761 + 1.1762 + 1.1763 +void XMLPrinter::PushUnknown( const char* value ) 1.1764 +{ 1.1765 + if ( elementJustOpened ) { 1.1766 + SealElement(); 1.1767 + } 1.1768 + if ( textDepth < 0 && !firstElement ) { 1.1769 + Print( "\n" ); 1.1770 + PrintSpace( depth ); 1.1771 + } 1.1772 + firstElement = false; 1.1773 + Print( "<!%s>", value ); 1.1774 +} 1.1775 + 1.1776 + 1.1777 +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) 1.1778 +{ 1.1779 + processEntities = doc.ProcessEntities(); 1.1780 + if ( doc.HasBOM() ) { 1.1781 + PushHeader( true, false ); 1.1782 + } 1.1783 + return true; 1.1784 +} 1.1785 + 1.1786 + 1.1787 +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) 1.1788 +{ 1.1789 + OpenElement( element.Name() ); 1.1790 + while ( attribute ) { 1.1791 + PushAttribute( attribute->Name(), attribute->Value() ); 1.1792 + attribute = attribute->Next(); 1.1793 + } 1.1794 + return true; 1.1795 +} 1.1796 + 1.1797 + 1.1798 +bool XMLPrinter::VisitExit( const XMLElement& ) 1.1799 +{ 1.1800 + CloseElement(); 1.1801 + return true; 1.1802 +} 1.1803 + 1.1804 + 1.1805 +bool XMLPrinter::Visit( const XMLText& text ) 1.1806 +{ 1.1807 + PushText( text.Value(), text.CData() ); 1.1808 + return true; 1.1809 +} 1.1810 + 1.1811 + 1.1812 +bool XMLPrinter::Visit( const XMLComment& comment ) 1.1813 +{ 1.1814 + PushComment( comment.Value() ); 1.1815 + return true; 1.1816 +} 1.1817 + 1.1818 +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) 1.1819 +{ 1.1820 + PushDeclaration( declaration.Value() ); 1.1821 + return true; 1.1822 +} 1.1823 + 1.1824 + 1.1825 +bool XMLPrinter::Visit( const XMLUnknown& unknown ) 1.1826 +{ 1.1827 + PushUnknown( unknown.Value() ); 1.1828 + return true; 1.1829 +}