diff --git a/externals/tinyxml/tinyxml2.cpp b/externals/tinyxml/tinyxml2.cpp index 2d3a1f7c1..f2c2e12cd 100644 --- a/externals/tinyxml/tinyxml2.cpp +++ b/externals/tinyxml/tinyxml2.cpp @@ -26,10 +26,81 @@ distribution. #include // yes, this one new style header, is in the Android SDK. #if defined(ANDROID_NDK) || defined(__QNXNTO__) # include +# include #else # include +# include #endif +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + + static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF static const char LF = LINE_FEED; static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out @@ -140,18 +211,18 @@ char* StrPair::ParseName( char* p ) if ( !p || !(*p) ) { return 0; } + if ( !XMLUtil::IsNameStartChar( *p ) ) { + return 0; + } char* const start = p; - - while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) { + ++p; + while ( *p && XMLUtil::IsNameChar( *p ) ) { ++p; } - if ( p > start ) { - Set( start, p, 0 ); - return p; - } - return 0; + Set( start, p, 0 ); + return p; } @@ -162,7 +233,7 @@ void StrPair::CollapseWhitespace() // Trim leading space. _start = XMLUtil::SkipWhiteSpace( _start ); - if ( _start && *_start ) { + if ( *_start ) { char* p = _start; // the read pointer char* q = _start; // the write pointer @@ -186,6 +257,8 @@ void StrPair::CollapseWhitespace() const char* StrPair::GetStr() { + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); if ( _flags & NEEDS_FLUSH ) { *_end = 0; _flags ^= NEEDS_FLUSH; @@ -226,15 +299,23 @@ const char* StrPair::GetStr() const int buflen = 10; char buf[buflen] = { 0 }; int len = 0; - p = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); - TIXMLASSERT( 0 <= len && len <= buflen ); - TIXMLASSERT( q + len <= p ); - memcpy( q, buf, len ); - q += len; + char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } } else { - int i=0; - for(; i(p); // Check for BOM: @@ -286,6 +371,7 @@ const char* XMLUtil::ReadBOM( const char* p, bool* bom ) *bom = true; p += 3; } + TIXMLASSERT( p ); return p; } @@ -309,7 +395,7 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length *length = 4; } else { - *length = 0; // This code won't covert this correctly anyway. + *length = 0; // This code won't convert this correctly anyway. return; } @@ -332,8 +418,9 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); - default: break; + default: + TIXMLASSERT( false ); } } @@ -345,65 +432,83 @@ const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) if ( *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); ptrdiff_t delta = 0; unsigned mult = 1; + static const char SEMICOLON = ';'; if ( *(p+2) == 'x' ) { // Hexadecimal. - if ( !*(p+3) ) { - return 0; - } - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) { + if ( !(*q) ) { return 0; } + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + delta = q-p; --q; while ( *q != 'x' ) { + unsigned int digit = 0; + if ( *q >= '0' && *q <= '9' ) { - ucs += mult * (*q - '0'); + digit = *q - '0'; } else if ( *q >= 'a' && *q <= 'f' ) { - ucs += mult * (*q - 'a' + 10); + digit = *q - 'a' + 10; } else if ( *q >= 'A' && *q <= 'F' ) { - ucs += mult * (*q - 'A' + 10 ); + digit = *q - 'A' + 10; } else { return 0; } + TIXMLASSERT( digit >= 0 && digit < 16); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); mult *= 16; --q; } } else { // Decimal. - if ( !*(p+2) ) { - return 0; - } - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) { + if ( !(*q) ) { return 0; } + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) { - ucs += mult * (*q - '0'); + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit >= 0 && digit < 10); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; } else { return 0; } + TIXMLASSERT( mult <= UINT_MAX / 10 ); mult *= 10; --q; } @@ -503,35 +608,31 @@ bool XMLUtil::ToDouble( const char* str, double* value ) char* XMLDocument::Identify( char* p, XMLNode** node ) { + TIXMLASSERT( node ); + TIXMLASSERT( p ); char* const start = p; p = XMLUtil::SkipWhiteSpace( p ); - if( !p || !*p ) { + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); return p; } - // What is this thing? - // These strings define the matching patters: + // These strings define the matching patterns: static const char* xmlHeader = { "VisitEnter( *this ) ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) { @@ -612,6 +716,9 @@ XMLNode::~XMLNode() const char* XMLNode::Value() const { + // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr. + if ( this->ToDocument() ) + return 0; return _value.GetStr(); } @@ -629,6 +736,7 @@ void XMLNode::SetValue( const char* str, bool staticMem ) void XMLNode::DeleteChildren() { while( _firstChild ) { + TIXMLASSERT( _lastChild ); TIXMLASSERT( _firstChild->_document == _document ); XMLNode* node = _firstChild; Unlink( node ); @@ -641,7 +749,9 @@ void XMLNode::DeleteChildren() void XMLNode::Unlink( XMLNode* child ) { + TIXMLASSERT( child ); TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); if ( child == _firstChild ) { _firstChild = _firstChild->_next; } @@ -661,6 +771,7 @@ void XMLNode::Unlink( XMLNode* child ) void XMLNode::DeleteChild( XMLNode* node ) { + TIXMLASSERT( node ); TIXMLASSERT( node->_document == _document ); TIXMLASSERT( node->_parent == this ); DeleteNode( node ); @@ -674,11 +785,7 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) TIXMLASSERT( false ); return 0; } - - if (addThis->_parent) - addThis->_parent->Unlink( addThis ); - else - addThis->_memPool->SetTracked(); + InsertChildPreamble( addThis ); if ( _lastChild ) { TIXMLASSERT( _firstChild ); @@ -708,11 +815,7 @@ XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) TIXMLASSERT( false ); return 0; } - - if (addThis->_parent) - addThis->_parent->Unlink( addThis ); - else - addThis->_memPool->SetTracked(); + InsertChildPreamble( addThis ); if ( _firstChild ) { TIXMLASSERT( _lastChild ); @@ -755,10 +858,7 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) // The last node or the only node. return InsertEndChild( addThis ); } - if (addThis->_parent) - addThis->_parent->Unlink( addThis ); - else - addThis->_memPool->SetTracked(); + InsertChildPreamble( addThis ); addThis->_prev = afterThis; addThis->_next = afterThis->_next; afterThis->_next->_prev = addThis; @@ -770,12 +870,12 @@ XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) -const XMLElement* XMLNode::FirstChildElement( const char* value ) const +const XMLElement* XMLNode::FirstChildElement( const char* name ) const { - for( XMLNode* node=_firstChild; node; node=node->_next ) { - XMLElement* element = node->ToElement(); + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElement(); if ( element ) { - if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { return element; } } @@ -784,12 +884,12 @@ const XMLElement* XMLNode::FirstChildElement( const char* value ) const } -const XMLElement* XMLNode::LastChildElement( const char* value ) const +const XMLElement* XMLNode::LastChildElement( const char* name ) const { - for( XMLNode* node=_lastChild; node; node=node->_prev ) { - XMLElement* element = node->ToElement(); + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElement(); if ( element ) { - if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { + if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) { return element; } } @@ -798,12 +898,12 @@ const XMLElement* XMLNode::LastChildElement( const char* value ) const } -const XMLElement* XMLNode::NextSiblingElement( const char* value ) const +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const { - for( XMLNode* node=this->_next; node; node = node->_next ) { + for( const XMLNode* node = _next; node; node = node->_next ) { const XMLElement* element = node->ToElement(); if ( element - && (!value || XMLUtil::StringEqual( value, node->Value() ))) { + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { return element; } } @@ -811,12 +911,12 @@ const XMLElement* XMLNode::NextSiblingElement( const char* value ) const } -const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const { - for( XMLNode* node=_prev; node; node = node->_prev ) { + for( const XMLNode* node = _prev; node; node = node->_prev ) { const XMLElement* element = node->ToElement(); if ( element - && (!value || XMLUtil::StringEqual( value, node->Value() ))) { + && (!name || XMLUtil::StringEqual( name, element->Name() ))) { return element; } } @@ -847,7 +947,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) XMLNode* node = 0; p = _document->Identify( p, &node ); - if ( p == 0 || node == 0 ) { + if ( node == 0 ) { break; } @@ -855,51 +955,58 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) p = node->ParseDeep( p, &endTag ); if ( !p ) { DeleteNode( node ); - node = 0; if ( !_document->Error() ) { _document->SetError( XML_ERROR_PARSING, 0, 0 ); } break; } - XMLElement* ele = node->ToElement(); - // We read the end tag. Return it to the parent. - if ( ele && ele->ClosingType() == XMLElement::CLOSING ) { - if ( parentEnd ) { - ele->_value.TransferTo( parentEnd ); - } - node->_memPool->SetTracked(); // created and then immediately deleted. - DeleteNode( node ); - return p; + XMLDeclaration* decl = node->ToDeclaration(); + if ( decl ) { + // A declaration can only be the first child of a document. + // Set error, if document already has children. + if ( !_document->NoChildren() ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0); + DeleteNode( decl ); + break; + } } - // Handle an end tag returned to this level. - // And handle a bunch of annoying errors. + XMLElement* ele = node->ToElement(); if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEnd ) { + ele->_value.TransferTo( parentEnd ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. bool mismatch = false; - if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) { - mismatch = true; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } } - else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) { - mismatch = true; - } - else if ( !endTag.Empty() ) { - if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { mismatch = true; } } if ( mismatch ) { - _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); - p = 0; + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 ); + DeleteNode( node ); + break; } } - if ( p == 0 ) { - DeleteNode( node ); - node = 0; - } - if ( node ) { - this->InsertEndChild( node ); - } + InsertEndChild( node ); } return 0; } @@ -914,6 +1021,17 @@ void XMLNode::DeleteNode( XMLNode* node ) pool->Free( node ); } +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if ( insertThis->_parent ) + insertThis->_parent->Unlink( insertThis ); + else + insertThis->_memPool->SetTracked(); +} + // --------- XMLText ---------- // char* XMLText::ParseDeep( char* p, StrPair* ) { @@ -928,16 +1046,16 @@ char* XMLText::ParseDeep( char* p, StrPair* ) else { int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { - flags |= StrPair::COLLAPSE_WHITESPACE; + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; } p = _value.ParseText( p, "<", flags ); - if ( !p ) { - _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); - } if ( p && *p ) { return p-1; } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); + } } return 0; } @@ -1138,7 +1256,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities ) // Skip white space before = p = XMLUtil::SkipWhiteSpace( p ); - if ( !p || *p != '=' ) { + if ( *p != '=' ) { return 0; } @@ -1474,7 +1592,7 @@ char* XMLElement::ParseAttributes( char* p ) // Read the attributes. while( p ) { p = XMLUtil::SkipWhiteSpace( p ); - if ( !p || !(*p) ) { + if ( !(*p) ) { _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); return 0; } @@ -1506,15 +1624,15 @@ char* XMLElement::ParseAttributes( char* p ) prevAttribute = attrib; } // end of the tag - else if ( *p == '/' && *(p+1) == '>' ) { - _closingType = CLOSED; - return p+2; // done; sealed element. - } - // end of the tag else if ( *p == '>' ) { ++p; break; } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } else { _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); return 0; @@ -1541,9 +1659,6 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair ) { // Read the element name. p = XMLUtil::SkipWhiteSpace( p ); - if ( !p ) { - return 0; - } // The closing element is the form. It is // parsed just like a regular element then deleted from @@ -1586,7 +1701,7 @@ bool XMLElement::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLElement* other = compare->ToElement(); - if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { const XMLAttribute* a=FirstAttribute(); const XMLAttribute* b=other->FirstAttribute(); @@ -1659,7 +1774,8 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : _errorStr2( 0 ), _charBuffer( 0 ) { - _document = this; // avoid warning about 'this' in initializer list + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; } @@ -1816,12 +1932,18 @@ XMLError XMLDocument::LoadFile( FILE* fp ) return _errorID; } - const size_t size = filelength; - if ( size == 0 ) { + if ( (unsigned long)filelength >= (size_t)-1 ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } + const size_t size = filelength; _charBuffer = new char[size+1]; size_t read = fread( _charBuffer, 1, size, fp ); if ( read != size ) { @@ -1831,15 +1953,7 @@ XMLError XMLDocument::LoadFile( FILE* fp ) _charBuffer[size] = 0; - const char* p = _charBuffer; - p = XMLUtil::SkipWhiteSpace( p ); - p = XMLUtil::ReadBOM( p, &_writeBOM ); - if ( !p || !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - - ParseDeep( _charBuffer + (p-_charBuffer), 0 ); + Parse(); return _errorID; } @@ -1859,6 +1973,9 @@ XMLError XMLDocument::SaveFile( const char* filename, bool compact ) XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) { + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + SetError( XML_NO_ERROR, 0, 0 ); XMLPrinter stream( fp, compact ); Print( &stream ); return _errorID; @@ -1867,7 +1984,6 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) XMLError XMLDocument::Parse( const char* p, size_t len ) { - const char* start = p; Clear(); if ( len == 0 || !p || !*p ) { @@ -1881,15 +1997,7 @@ XMLError XMLDocument::Parse( const char* p, size_t len ) memcpy( _charBuffer, p, len ); _charBuffer[len] = 0; - p = XMLUtil::SkipWhiteSpace( p ); - p = XMLUtil::ReadBOM( p, &_writeBOM ); - if ( !p || !*p ) { - SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); - return _errorID; - } - - ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc. - ParseDeep( _charBuffer+delta, 0 ); + Parse(); if ( Error() ) { // clean up now essentially dangling memory. // and the parse fail can put objects in the @@ -1906,11 +2014,13 @@ XMLError XMLDocument::Parse( const char* p, size_t len ) void XMLDocument::Print( XMLPrinter* streamer ) const { - XMLPrinter stdStreamer( stdout ); - if ( !streamer ) { - streamer = &stdStreamer; + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); } - Accept( streamer ); } @@ -1925,7 +2035,9 @@ void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) const char* XMLDocument::ErrorName() const { TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT ); - return _errorNames[_errorID]; + const char* errorName = _errorNames[_errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; } void XMLDocument::PrintError() const @@ -1942,11 +2054,27 @@ void XMLDocument::PrintError() const TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); } + // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that + // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning + TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX ); printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n", - _errorID, ErrorName(), buf1, buf2 ); + static_cast( _errorID ), ErrorName(), buf1, buf2 ); } } +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0 ); +} XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : _elementJustOpened( false ), @@ -1962,16 +2090,13 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : _restrictedEntityFlag[i] = false; } for( int i=0; i'] = true; // not required, but consistency is nice + _restrictedEntityFlag[(unsigned char)'&'] = true; + _restrictedEntityFlag[(unsigned char)'<'] = true; + _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice _buffer.Push( 0 ); } @@ -1985,34 +2110,14 @@ void XMLPrinter::Print( const char* format, ... ) vfprintf( _fp, format, va ); } else { -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - #if defined(WINCE) - int len = 512; - do { - len = len*2; - char* str = new char[len](); - len = _vsnprintf(str, len, format, va); - delete[] str; - }while (len < 0); - #else - int len = _vscprintf( format, va ); - #endif -#else - int len = vsnprintf( 0, 0, format, va ); -#endif + const int len = TIXML_VSCPRINTF( format, va ); // Close out and re-start the va-args va_end( va ); + TIXMLASSERT( len >= 0 ); va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - #if defined(WINCE) - _vsnprintf( p, len+1, format, va ); - #else - vsnprintf_s( p, len+1, _TRUNCATE, format, va ); - #endif -#else - vsnprintf( p, len+1, format, va ); -#endif + TIXML_VSNPRINTF( p, len+1, format, va ); } va_end( va ); } @@ -2030,35 +2135,47 @@ void XMLPrinter::PrintString( const char* p, bool restricted ) { // Look for runs of bytes between entities to print. const char* q = p; - const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; if ( _processEntities ) { + const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; while ( *q ) { + TIXMLASSERT( p <= q ); // Remember, char is sometimes signed. (How many times has that bitten me?) if ( *q > 0 && *q < ENTITY_RANGE ) { // Check for entities. If one is found, flush // the stream up until the entity, write the // entity, and keep looking. - if ( flag[(unsigned)(*q)] ) { + if ( flag[(unsigned char)(*q)] ) { while ( p < q ) { - Print( "%c", *p ); - ++p; + const size_t delta = q - p; + // %.*s accepts type int as "precision" + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + Print( "%.*s", toPrint, p ); + p += toPrint; } + bool entityPatternPrinted = false; for( int i=0; i 0) ) { + TIXMLASSERT( p <= q ); + if ( !_processEntities || ( p < q ) ) { Print( "%s", p ); } } @@ -2078,9 +2195,7 @@ void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) void XMLPrinter::OpenElement( const char* name, bool compactMode ) { - if ( _elementJustOpened ) { - SealElement(); - } + SealElementIfJustOpened(); _stack.Push( name ); if ( _textDepth < 0 && !_firstElement && !compactMode ) { @@ -2164,8 +2279,11 @@ void XMLPrinter::CloseElement( bool compactMode ) } -void XMLPrinter::SealElement() +void XMLPrinter::SealElementIfJustOpened() { + if ( !_elementJustOpened ) { + return; + } _elementJustOpened = false; Print( ">" ); } @@ -2175,13 +2293,9 @@ void XMLPrinter::PushText( const char* text, bool cdata ) { _textDepth = _depth-1; - if ( _elementJustOpened ) { - SealElement(); - } + SealElementIfJustOpened(); if ( cdata ) { - Print( "" ); + Print( "", text ); } else { PrintString( text, true ); @@ -2230,9 +2344,7 @@ void XMLPrinter::PushText( double value ) void XMLPrinter::PushComment( const char* comment ) { - if ( _elementJustOpened ) { - SealElement(); - } + SealElementIfJustOpened(); if ( _textDepth < 0 && !_firstElement && !_compactMode) { Print( "\n" ); PrintSpace( _depth ); @@ -2244,9 +2356,7 @@ void XMLPrinter::PushComment( const char* comment ) void XMLPrinter::PushDeclaration( const char* value ) { - if ( _elementJustOpened ) { - SealElement(); - } + SealElementIfJustOpened(); if ( _textDepth < 0 && !_firstElement && !_compactMode) { Print( "\n" ); PrintSpace( _depth ); @@ -2258,9 +2368,7 @@ void XMLPrinter::PushDeclaration( const char* value ) void XMLPrinter::PushUnknown( const char* value ) { - if ( _elementJustOpened ) { - SealElement(); - } + SealElementIfJustOpened(); if ( _textDepth < 0 && !_firstElement && !_compactMode) { Print( "\n" ); PrintSpace( _depth ); @@ -2282,8 +2390,11 @@ bool XMLPrinter::VisitEnter( const XMLDocument& doc ) bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) { - const XMLElement* parentElem = element.Parent()->ToElement(); - bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode; + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; OpenElement( element.Name(), compactMode ); while ( attribute ) { PushAttribute( attribute->Name(), attribute->Value() ); diff --git a/externals/tinyxml/tinyxml2.h b/externals/tinyxml/tinyxml2.h index dd1b2cd23..b873e3497 100644 --- a/externals/tinyxml/tinyxml2.h +++ b/externals/tinyxml/tinyxml2.h @@ -30,14 +30,12 @@ distribution. # include # include # include -# include #else # include # include # include # include # include -# include #endif /* @@ -77,7 +75,8 @@ distribution. #if defined(DEBUG) # if defined(_MSC_VER) -# define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } //if ( !(x)) WinDebugBreak() # elif defined (ANDROID_NDK) # include # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } @@ -90,39 +89,11 @@ distribution. #endif -#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) -// Microsoft visual studio, version 2005 and higher. -/*int _snprintf_s( - char *buffer, - size_t sizeOfBuffer, - size_t count, - const char *format [, - argument] ... -);*/ -inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) -{ - va_list va; - va_start( va, format ); - int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); - va_end( va ); - return result; -} -#define TIXML_SSCANF sscanf_s -#elif defined WINCE -#define TIXML_SNPRINTF _snprintf -#define TIXML_SSCANF sscanf -#else -// GCC version 3 and higher -//#warning( "Using sn* functions." ) -#define TIXML_SNPRINTF snprintf -#define TIXML_SSCANF sscanf -#endif - /* Versioning, past 1.0.14: http://semver.org/ */ -static const int TIXML2_MAJOR_VERSION = 2; -static const int TIXML2_MINOR_VERSION = 2; +static const int TIXML2_MAJOR_VERSION = 3; +static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0; namespace tinyxml2 @@ -148,7 +119,7 @@ public: enum { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, - COLLAPSE_WHITESPACE = 0x04, + NEEDS_WHITESPACE_COLLAPSING = 0x04, TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, @@ -210,13 +181,13 @@ private: Has a small initial memory pool, so that low or no usage will not cause a call to new/delete */ -template +template class DynArray { public: - DynArray< T, INIT >() { + DynArray() { _mem = _pool; - _allocated = INIT; + _allocated = INITIAL_SIZE; _size = 0; } @@ -231,11 +202,14 @@ public: } void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); EnsureCapacity( _size+1 ); _mem[_size++] = t; } T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); EnsureCapacity( _size+count ); T* ret = &_mem[_size]; _size += count; @@ -243,6 +217,7 @@ public: } T Pop() { + TIXMLASSERT( _size > 0 ); return _mem[--_size]; } @@ -271,24 +246,33 @@ public: } int Size() const { + TIXMLASSERT( _size >= 0 ); return _size; } int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); return _allocated; } const T* Mem() const { + TIXMLASSERT( _mem ); return _mem; } T* Mem() { + TIXMLASSERT( _mem ); return _mem; } private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); int newAllocated = cap * 2; T* newMem = new T[newAllocated]; memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs @@ -301,7 +285,7 @@ private: } T* _mem; - T _pool[INIT]; + T _pool[INITIAL_SIZE]; int _allocated; // objects allocated int _size; // number objects in use }; @@ -418,6 +402,9 @@ public: enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + union Chunk { Chunk* next; char mem[SIZE]; @@ -531,9 +518,11 @@ class XMLUtil { public: static const char* SkipWhiteSpace( const char* p ) { + TIXMLASSERT( p ); while( IsWhiteSpace(*p) ) { ++p; } + TIXMLASSERT( p ); return p; } static char* SkipWhiteSpace( char* p ) { @@ -547,9 +536,14 @@ public: } inline static bool IsNameStartChar( unsigned char ch ) { - return ( ( ch < 128 ) ? isalpha( ch ) : 1 ) - || ch == ':' - || ch == '_'; + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; } inline static bool IsNameChar( unsigned char ch ) { @@ -560,10 +554,10 @@ public: } inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { - int n = 0; if ( p == q ) { return true; } + int n = 0; while( *p && *q && *p == *q && n(const_cast(this)->FirstChildElement( value )); + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); } /// Get the last child node, or null if none exists. @@ -739,16 +735,16 @@ public: } XMLNode* LastChild() { - return const_cast(const_cast(this)->LastChild() ); + return _lastChild; } /** Get the last child element or optionally the last child element with the specified name. */ - const XMLElement* LastChildElement( const char* value=0 ) const; + const XMLElement* LastChildElement( const char* name = 0 ) const; - XMLElement* LastChildElement( const char* value=0 ) { - return const_cast(const_cast(this)->LastChildElement(value) ); + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); } /// Get the previous (left) sibling node of this node. @@ -761,10 +757,10 @@ public: } /// Get the previous (left) sibling element of this node, with an optionally supplied name. - const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; - XMLElement* PreviousSiblingElement( const char* value=0 ) { - return const_cast(const_cast(this)->PreviousSiblingElement( value ) ); + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); } /// Get the next (right) sibling node of this node. @@ -777,10 +773,10 @@ public: } /// Get the next (right) sibling element of this node, with an optionally supplied name. - const XMLElement* NextSiblingElement( const char* value=0 ) const; + const XMLElement* NextSiblingElement( const char* name = 0 ) const; - XMLElement* NextSiblingElement( const char* value=0 ) { - return const_cast(const_cast(this)->NextSiblingElement( value ) ); + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); } /** @@ -866,14 +862,11 @@ public: */ virtual bool Accept( XMLVisitor* visitor ) const = 0; - // internal - virtual char* ParseDeep( char*, StrPair* ); - protected: XMLNode( XMLDocument* ); virtual ~XMLNode(); - XMLNode( const XMLNode& ); // not supported - XMLNode& operator=( const XMLNode& ); // not supported + + virtual char* ParseDeep( char*, StrPair* ); XMLDocument* _document; XMLNode* _parent; @@ -889,6 +882,10 @@ private: MemPool* _memPool; void Unlink( XMLNode* child ); static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported }; @@ -927,18 +924,20 @@ public: return _isCData; } - char* ParseDeep( char*, StrPair* endTag ); virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} - XMLText( const XMLText& ); // not supported - XMLText& operator=( const XMLText& ); // not supported + + char* ParseDeep( char*, StrPair* endTag ); private: bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported }; @@ -956,17 +955,18 @@ public: virtual bool Accept( XMLVisitor* visitor ) const; - char* ParseDeep( char*, StrPair* endTag ); virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: XMLComment( XMLDocument* doc ); virtual ~XMLComment(); - XMLComment( const XMLComment& ); // not supported - XMLComment& operator=( const XMLComment& ); // not supported + + char* ParseDeep( char*, StrPair* endTag ); private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported }; @@ -994,13 +994,16 @@ public: virtual bool Accept( XMLVisitor* visitor ) const; - char* ParseDeep( char*, StrPair* endTag ); virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration& operator=( const XMLDeclaration& ); // not supported }; @@ -1026,13 +1029,16 @@ public: virtual bool Accept( XMLVisitor* visitor ) const; - char* ParseDeep( char*, StrPair* endTag ); virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; protected: XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); + + char* ParseDeep( char*, StrPair* endTag ); + +private: XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown& operator=( const XMLUnknown& ); // not supported }; @@ -1481,10 +1487,12 @@ public: int ClosingType() const { return _closingType; } - char* ParseDeep( char* p, StrPair* endTag ); virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual bool ShallowEqual( const XMLNode* compare ) const; +protected: + char* ParseDeep( char* p, StrPair* endTag ); + private: XMLElement( XMLDocument* doc ); virtual ~XMLElement(); @@ -1528,9 +1536,11 @@ public: ~XMLDocument(); virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); return this; } virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); return this; } @@ -1725,6 +1735,8 @@ private: MemPoolT< sizeof(XMLComment) > _commentPool; static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); }; @@ -1809,32 +1821,32 @@ public: return XMLHandle( _node ? _node->FirstChild() : 0 ); } /// Get the first child element of this handle. - XMLHandle FirstChildElement( const char* value=0 ) { - return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 ); + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); } /// Get the last child of this handle. XMLHandle LastChild() { return XMLHandle( _node ? _node->LastChild() : 0 ); } /// Get the last child element of this handle. - XMLHandle LastChildElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 ); + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); } /// Get the previous sibling of this handle. XMLHandle PreviousSibling() { return XMLHandle( _node ? _node->PreviousSibling() : 0 ); } /// Get the previous sibling element of this handle. - XMLHandle PreviousSiblingElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } /// Get the next sibling of this handle. XMLHandle NextSibling() { return XMLHandle( _node ? _node->NextSibling() : 0 ); } /// Get the next sibling element of this handle. - XMLHandle NextSiblingElement( const char* _value=0 ) { - return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } /// Safe cast to XMLNode. This can return null. @@ -1888,26 +1900,26 @@ public: const XMLConstHandle FirstChild() const { return XMLConstHandle( _node ? _node->FirstChild() : 0 ); } - const XMLConstHandle FirstChildElement( const char* value=0 ) const { - return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 ); + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); } const XMLConstHandle LastChild() const { return XMLConstHandle( _node ? _node->LastChild() : 0 ); } - const XMLConstHandle LastChildElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 ); + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); } const XMLConstHandle PreviousSibling() const { return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); } - const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } const XMLConstHandle NextSibling() const { return XMLConstHandle( _node ? _node->NextSibling() : 0 ); } - const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { - return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } @@ -2066,7 +2078,7 @@ protected: virtual void PrintSpace( int depth ); void Print( const char* format, ... ); - void SealElement(); + void SealElementIfJustOpened(); bool _elementJustOpened; DynArray< const char*, 10 > _stack;