diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index 57cf62ad4aa..0fe281bbfde 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -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) @@ -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(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) @@ -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; }