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