Merge pull request #787 from jsenn/feature/large-file-support

Added support for files larger than ~2GB
This commit is contained in:
Lee Thomason
2020-03-10 14:21:04 -07:00
committed by GitHub

View File

@@ -100,6 +100,20 @@ distribution.
#define TIXML_SSCANF sscanf #define TIXML_SSCANF sscanf
#endif #endif
#if defined(_WIN64)
#define TIXML_FSEEK _fseeki64
#define TIXML_FTELL _ftelli64
#elif defined(__APPLE__)
#define TIXML_FSEEK fseeko
#define TIXML_FTELL ftello
#elif defined(__x86_64__)
#define TIXML_FSEEK fseeko64
#define TIXML_FTELL ftello64
#else
#define TIXML_FSEEK fseek
#define TIXML_FTELL ftell
#endif
static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF static const char LINE_FEED = static_cast<char>(0x0a); // all line endings are normalized to LF
static const char LF = LINE_FEED; static const char LF = LINE_FEED;
@@ -2286,49 +2300,34 @@ XMLError XMLDocument::LoadFile( const char* filename )
return _errorID; return _errorID;
} }
// This is likely overengineered template art to have a check that unsigned long value incremented
// by one still fits into size_t. If size_t type is larger than unsigned long type
// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
// types sizes relate to each other.
template
<bool = (sizeof(unsigned long) >= sizeof(size_t))>
struct LongFitsIntoSizeTMinusOne {
static bool Fits( unsigned long value )
{
return value < static_cast<size_t>(-1);
}
};
template <>
struct LongFitsIntoSizeTMinusOne<false> {
static bool Fits( unsigned long )
{
return true;
}
};
XMLError XMLDocument::LoadFile( FILE* fp ) XMLError XMLDocument::LoadFile( FILE* fp )
{ {
Clear(); Clear();
fseek( fp, 0, SEEK_SET ); TIXML_FSEEK( fp, 0, SEEK_SET );
if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
return _errorID; return _errorID;
} }
fseek( fp, 0, SEEK_END ); TIXML_FSEEK( fp, 0, SEEK_END );
const long filelength = ftell( fp );
fseek( fp, 0, SEEK_SET ); unsigned long long filelength;
if ( filelength == -1L ) { {
const long long fileLengthSigned = TIXML_FTELL( fp );
TIXML_FSEEK( fp, 0, SEEK_SET );
if ( fileLengthSigned == -1L ) {
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
return _errorID; return _errorID;
} }
TIXMLASSERT( filelength >= 0 ); TIXMLASSERT( fileLengthSigned >= 0 );
filelength = static_cast<unsigned long long>(fileLengthSigned);
}
if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { const size_t maxSizeT = static_cast<size_t>(-1);
// We'll do the comparison as an unsigned long long, because that's guaranteed to be at
// least 8 bytes, even on a 32-bit platform.
if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
// Cannot handle files which won't fit in buffer together with null terminator // Cannot handle files which won't fit in buffer together with null terminator
SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
return _errorID; return _errorID;
@@ -2339,7 +2338,7 @@ XMLError XMLDocument::LoadFile( FILE* fp )
return _errorID; return _errorID;
} }
const size_t size = filelength; const size_t size = static_cast<size_t>(filelength);
TIXMLASSERT( _charBuffer == 0 ); TIXMLASSERT( _charBuffer == 0 );
_charBuffer = new char[size+1]; _charBuffer = new char[size+1];
const size_t read = fread( _charBuffer, 1, size, fp ); const size_t read = fread( _charBuffer, 1, size, fp );