mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-14 03:58:18 +00:00
Check for errors when reading and decompressing datafile data
Check if datafile data cannot be read entirely (according to the data size specified in the header) and check for decompression errors. In case of errors, let `GetData` return `nullptr` and `GetDataSize` return `0` for the respective index. Internally the decompressed size is set to `-1` for data which failed to load, so loading of those data will not be attempted again because it would only fail again and can cause additional log messages.
This commit is contained in:
parent
fd13ae5fd5
commit
7069d74beb
|
@ -295,7 +295,10 @@ int CDataFileReader::GetDataSize(int Index) const
|
||||||
return GetFileDataSize(Index);
|
return GetFileDataSize(Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_pDataFile->m_pDataSizes[Index];
|
const int Size = m_pDataFile->m_pDataSizes[Index];
|
||||||
|
if(Size < 0)
|
||||||
|
return 0; // summarize all errors as zero size
|
||||||
|
return Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *CDataFileReader::GetDataImpl(int Index, int Swap)
|
void *CDataFileReader::GetDataImpl(int Index, int Swap)
|
||||||
|
@ -311,45 +314,73 @@ void *CDataFileReader::GetDataImpl(int Index, int Swap)
|
||||||
// load it if needed
|
// load it if needed
|
||||||
if(!m_pDataFile->m_ppDataPtrs[Index])
|
if(!m_pDataFile->m_ppDataPtrs[Index])
|
||||||
{
|
{
|
||||||
|
// don't try to load again if it previously failed
|
||||||
|
if(m_pDataFile->m_pDataSizes[Index] < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// fetch the data size
|
// fetch the data size
|
||||||
int DataSize = GetFileDataSize(Index);
|
unsigned DataSize = GetFileDataSize(Index);
|
||||||
#if defined(CONF_ARCH_ENDIAN_BIG)
|
#if defined(CONF_ARCH_ENDIAN_BIG)
|
||||||
int SwapSize = DataSize;
|
unsigned SwapSize = DataSize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(m_pDataFile->m_Header.m_Version == 4)
|
if(m_pDataFile->m_Header.m_Version == 4)
|
||||||
{
|
{
|
||||||
// v4 has compressed data
|
// v4 has compressed data
|
||||||
void *pTemp = malloc(DataSize);
|
const unsigned OriginalUncompressedSize = m_pDataFile->m_Info.m_pDataSizes[Index];
|
||||||
unsigned long UncompressedSize = m_pDataFile->m_Info.m_pDataSizes[Index];
|
unsigned long UncompressedSize = OriginalUncompressedSize;
|
||||||
unsigned long s;
|
|
||||||
|
|
||||||
log_trace("datafile", "loading data index=%d size=%d uncompressed=%lu", Index, DataSize, UncompressedSize);
|
log_trace("datafile", "loading data. index=%d size=%u uncompressed=%u", Index, DataSize, OriginalUncompressedSize);
|
||||||
m_pDataFile->m_ppDataPtrs[Index] = (char *)malloc(UncompressedSize);
|
|
||||||
m_pDataFile->m_pDataSizes[Index] = UncompressedSize;
|
|
||||||
|
|
||||||
// read the compressed data
|
// read the compressed data
|
||||||
io_seek(m_pDataFile->m_File, m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index], IOSEEK_START);
|
void *pCompressedData = malloc(DataSize);
|
||||||
io_read(m_pDataFile->m_File, pTemp, DataSize);
|
unsigned ActualDataSize = 0;
|
||||||
|
if(io_seek(m_pDataFile->m_File, m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index], IOSEEK_START) == 0)
|
||||||
|
ActualDataSize = io_read(m_pDataFile->m_File, pCompressedData, DataSize);
|
||||||
|
if(DataSize != ActualDataSize)
|
||||||
|
{
|
||||||
|
log_error("datafile", "truncation error, could not read all data. index=%d wanted=%u got=%u", Index, DataSize, ActualDataSize);
|
||||||
|
free(pCompressedData);
|
||||||
|
m_pDataFile->m_ppDataPtrs[Index] = nullptr;
|
||||||
|
m_pDataFile->m_pDataSizes[Index] = -1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompress the data
|
||||||
|
m_pDataFile->m_ppDataPtrs[Index] = (char *)malloc(UncompressedSize);
|
||||||
|
m_pDataFile->m_pDataSizes[Index] = UncompressedSize;
|
||||||
|
const int Result = uncompress((Bytef *)m_pDataFile->m_ppDataPtrs[Index], &UncompressedSize, (Bytef *)pCompressedData, DataSize);
|
||||||
|
free(pCompressedData);
|
||||||
|
if(Result != Z_OK || UncompressedSize != OriginalUncompressedSize)
|
||||||
|
{
|
||||||
|
log_error("datafile", "uncompress error. result=%d wanted=%u got=%lu", Result, OriginalUncompressedSize, UncompressedSize);
|
||||||
|
free(m_pDataFile->m_ppDataPtrs[Index]);
|
||||||
|
m_pDataFile->m_ppDataPtrs[Index] = nullptr;
|
||||||
|
m_pDataFile->m_pDataSizes[Index] = -1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// decompress the data, TODO: check for errors
|
|
||||||
s = UncompressedSize;
|
|
||||||
uncompress((Bytef *)m_pDataFile->m_ppDataPtrs[Index], &s, (Bytef *)pTemp, DataSize);
|
|
||||||
#if defined(CONF_ARCH_ENDIAN_BIG)
|
#if defined(CONF_ARCH_ENDIAN_BIG)
|
||||||
SwapSize = s;
|
SwapSize = UncompressedSize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// clean up the temporary buffers
|
|
||||||
free(pTemp);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// load the data
|
// load the data
|
||||||
log_trace("datafile", "loading data index=%d size=%d", Index, DataSize);
|
log_trace("datafile", "loading data. index=%d size=%d", Index, DataSize);
|
||||||
m_pDataFile->m_ppDataPtrs[Index] = (char *)malloc(DataSize);
|
m_pDataFile->m_ppDataPtrs[Index] = static_cast<char *>(malloc(DataSize));
|
||||||
m_pDataFile->m_pDataSizes[Index] = DataSize;
|
m_pDataFile->m_pDataSizes[Index] = DataSize;
|
||||||
io_seek(m_pDataFile->m_File, m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index], IOSEEK_START);
|
unsigned ActualDataSize = 0;
|
||||||
io_read(m_pDataFile->m_File, m_pDataFile->m_ppDataPtrs[Index], DataSize);
|
if(io_seek(m_pDataFile->m_File, m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index], IOSEEK_START) == 0)
|
||||||
|
ActualDataSize = io_read(m_pDataFile->m_File, m_pDataFile->m_ppDataPtrs[Index], DataSize);
|
||||||
|
if(DataSize != ActualDataSize)
|
||||||
|
{
|
||||||
|
log_error("datafile", "truncation error, could not read all data. index=%d wanted=%u got=%u", Index, DataSize, ActualDataSize);
|
||||||
|
free(m_pDataFile->m_ppDataPtrs[Index]);
|
||||||
|
m_pDataFile->m_ppDataPtrs[Index] = nullptr;
|
||||||
|
m_pDataFile->m_pDataSizes[Index] = -1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONF_ARCH_ENDIAN_BIG)
|
#if defined(CONF_ARCH_ENDIAN_BIG)
|
||||||
|
@ -373,10 +404,7 @@ void *CDataFileReader::GetDataSwapped(int Index)
|
||||||
|
|
||||||
void CDataFileReader::ReplaceData(int Index, char *pData, size_t Size)
|
void CDataFileReader::ReplaceData(int Index, char *pData, size_t Size)
|
||||||
{
|
{
|
||||||
// make sure the data has been loaded
|
free(m_pDataFile->m_ppDataPtrs[Index]);
|
||||||
GetDataImpl(Index, 0);
|
|
||||||
|
|
||||||
UnloadData(Index);
|
|
||||||
m_pDataFile->m_ppDataPtrs[Index] = pData;
|
m_pDataFile->m_ppDataPtrs[Index] = pData;
|
||||||
m_pDataFile->m_pDataSizes[Index] = Size;
|
m_pDataFile->m_pDataSizes[Index] = Size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
void *GetData(int Index);
|
void *GetData(int Index);
|
||||||
void *GetDataSwapped(int Index); // makes sure that the data is 32bit LE ints when saved
|
void *GetDataSwapped(int Index); // makes sure that the data is 32bit LE ints when saved
|
||||||
int GetDataSize(int Index) const;
|
int GetDataSize(int Index) const;
|
||||||
void ReplaceData(int Index, char *pData, size_t Size);
|
void ReplaceData(int Index, char *pData, size_t Size); // memory for data must have been allocated with malloc
|
||||||
void UnloadData(int Index);
|
void UnloadData(int Index);
|
||||||
int NumData() const;
|
int NumData() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue