Skip to content

Commit

Permalink
Check for errors when reading and decompressing datafile data
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Robyt3 committed Jul 26, 2023
1 parent d3cd79a commit fd2ef44
Showing 1 changed file with 50 additions and 24 deletions.
74 changes: 50 additions & 24 deletions src/engine/shared/datafile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ int CDataFileReader::GetDataSize(int Index) const
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, bool Swap)
Expand All @@ -323,45 +326,71 @@ void *CDataFileReader::GetDataImpl(int Index, bool Swap)
// load it if needed
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
int DataSize = GetFileDataSize(Index);
unsigned DataSize = GetFileDataSize(Index);
#if defined(CONF_ARCH_ENDIAN_BIG)
int SwapSize = DataSize;
unsigned SwapSize = DataSize;
#endif

if(m_pDataFile->m_Header.m_Version == 4)
{
// v4 has compressed data
void *pTemp = malloc(DataSize);
unsigned long UncompressedSize = m_pDataFile->m_Info.m_pDataSizes[Index];
unsigned long s;
const unsigned OriginalUncompressedSize = m_pDataFile->m_Info.m_pDataSizes[Index];
unsigned long UncompressedSize = OriginalUncompressedSize;

log_trace("datafile", "loading data index=%d size=%d uncompressed=%lu", Index, DataSize, UncompressedSize);
m_pDataFile->m_ppDataPtrs[Index] = (char *)malloc(UncompressedSize);
m_pDataFile->m_pDataSizes[Index] = UncompressedSize;
log_trace("datafile", "loading data. index=%d size=%u uncompressed=%u", Index, DataSize, OriginalUncompressedSize);

// read the compressed data
void *pCompressedData = malloc(DataSize);
m_pMemoryReader->SetPosition(m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index]);
m_pMemoryReader->Read(pTemp, DataSize);
const unsigned ActualDataSize = m_pMemoryReader->Read(pCompressedData, DataSize);
if(DataSize != ActualDataSize)
{
dbg_msg("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)
{
dbg_msg("datafile", "uncompress error %d, size %lu", Result, 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)
SwapSize = s;
SwapSize = UncompressedSize;
#endif

// clean up the temporary buffers
free(pTemp);
}
else
{
// load the data
log_trace("datafile", "loading data index=%d size=%d", Index, DataSize);
m_pDataFile->m_ppDataPtrs[Index] = (char *)malloc(DataSize);
log_trace("datafile", "loading data. index=%d size=%d", Index, DataSize);
m_pDataFile->m_ppDataPtrs[Index] = static_cast<char *>(malloc(DataSize));
m_pDataFile->m_pDataSizes[Index] = DataSize;
m_pMemoryReader->SetPosition(m_pDataFile->m_DataStartOffset + m_pDataFile->m_Info.m_pDataOffsets[Index]);
m_pMemoryReader->Read(m_pDataFile->m_ppDataPtrs[Index], DataSize);
const unsigned ActualDataSize = m_pMemoryReader->Read(m_pDataFile->m_ppDataPtrs[Index], DataSize);
if(DataSize != ActualDataSize)
{
dbg_msg("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)
Expand All @@ -385,10 +414,7 @@ void *CDataFileReader::GetDataSwapped(int Index)

void CDataFileReader::ReplaceData(int Index, char *pData, size_t Size)
{
// make sure the data has been loaded
GetDataImpl(Index, 0);

UnloadData(Index);
free(m_pDataFile->m_ppDataPtrs[Index]);
m_pDataFile->m_ppDataPtrs[Index] = pData;
m_pDataFile->m_pDataSizes[Index] = Size;
}
Expand Down

0 comments on commit fd2ef44

Please sign in to comment.