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