diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04f19ef68..518235f66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1066,8 +1066,6 @@ set (PCH_SOURCES common/utility/m_alloc.cpp common/utility/utf8.cpp common/utility/palette.cpp - common/utility/files.cpp - common/utility/files_decompress.cpp common/utility/memarena.cpp common/utility/cmdlib.cpp common/utility/configfile.cpp @@ -1084,19 +1082,6 @@ set (PCH_SOURCES common/thirdparty/libsmackerdec/src/HuffmanVLC.cpp common/thirdparty/libsmackerdec/src/LogError.cpp common/thirdparty/libsmackerdec/src/SmackerDecoder.cpp - common/filesystem/filesystem.cpp - common/filesystem/ancientzip.cpp - common/filesystem/file_7z.cpp - common/filesystem/file_grp.cpp - common/filesystem/file_lump.cpp - common/filesystem/file_rff.cpp - common/filesystem/file_wad.cpp - common/filesystem/file_zip.cpp - common/filesystem/file_pak.cpp - common/filesystem/file_whres.cpp - common/filesystem/file_ssi.cpp - common/filesystem/file_directory.cpp - common/filesystem/resourcefile.cpp common/engine/cycler.cpp common/engine/d_event.cpp common/engine/date.cpp @@ -1220,6 +1205,23 @@ set( ZDOOM_SOURCES common/thirdparty/math/tan.c common/thirdparty/math/tanh.c common/thirdparty/math/fastsin.cpp + + common/filesystem/filesystem.cpp + common/filesystem/ancientzip.cpp + common/filesystem/file_7z.cpp + common/filesystem/file_grp.cpp + common/filesystem/file_lump.cpp + common/filesystem/file_rff.cpp + common/filesystem/file_wad.cpp + common/filesystem/file_zip.cpp + common/filesystem/file_pak.cpp + common/filesystem/file_whres.cpp + common/filesystem/file_ssi.cpp + common/filesystem/file_directory.cpp + common/filesystem/resourcefile.cpp + common/filesystem/files.cpp + common/filesystem/files_decompress.cpp + ) set( ZDOOM_NONPCH_SOURCES ${ZDOOM_SOURCES} ) diff --git a/src/common/filesystem/ancientzip.cpp b/src/common/filesystem/ancientzip.cpp index 0088d1f00..80f0c6093 100644 --- a/src/common/filesystem/ancientzip.cpp +++ b/src/common/filesystem/ancientzip.cpp @@ -310,7 +310,7 @@ int FZipExploder::Explode(unsigned char *out, unsigned int outsize, len += minMatchLen; dist++; if (bIdx + len > outsize) { - throw CExplosionError("Not enough output space"); + return -1; } if ((unsigned int)dist > bIdx) { /* Anything before the first input byte is zero. */ diff --git a/src/common/filesystem/ancientzip.h b/src/common/filesystem/ancientzip.h index 6241f775d..57b0f3584 100644 --- a/src/common/filesystem/ancientzip.h +++ b/src/common/filesystem/ancientzip.h @@ -1,6 +1,5 @@ #pragma once #include "files.h" -#include "engineerrors.h" class FZipExploder { @@ -42,10 +41,4 @@ public: int Explode(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize, int flags); }; -class CExplosionError : public CRecoverableError -{ -public: - CExplosionError(const char *message) : CRecoverableError(message) {} -}; - int ShrinkLoop(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize); \ No newline at end of file diff --git a/src/common/filesystem/file_7z.cpp b/src/common/filesystem/file_7z.cpp index 2bdd2e38f..405e9b919 100644 --- a/src/common/filesystem/file_7z.cpp +++ b/src/common/filesystem/file_7z.cpp @@ -168,7 +168,7 @@ struct F7ZLump : public FResourceLump { int Position; - virtual int FillCache(); + virtual int FillCache() override; }; @@ -340,7 +340,11 @@ F7ZFile::~F7ZFile() int F7ZLump::FillCache() { Cache = new char[LumpSize]; - static_cast(Owner)->Archive->Extract(Position, Cache); + SRes code = static_cast(Owner)->Archive->Extract(Position, Cache); + if (code != SZ_OK) + { + throw FileSystemException("Error %d reading from 7z archive", code); + } RefCount = 1; return 1; } diff --git a/src/common/filesystem/file_directory.cpp b/src/common/filesystem/file_directory.cpp index f0ba89bfc..00b1e7a12 100644 --- a/src/common/filesystem/file_directory.cpp +++ b/src/common/filesystem/file_directory.cpp @@ -250,10 +250,13 @@ int FDirectoryLump::FillCache() Cache = new char[LumpSize]; if (!fr.OpenFile(mFullPath)) { - memset(Cache, 0, LumpSize); - return 0; + throw FileSystemException("unable to open file"); + } + auto read = fr.Read(Cache, LumpSize); + if (read != LumpSize) + { + throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); } - fr.Read(Cache, LumpSize); RefCount = 1; return 1; } diff --git a/src/common/filesystem/file_rff.cpp b/src/common/filesystem/file_rff.cpp index 8d59749a5..67c26def1 100644 --- a/src/common/filesystem/file_rff.cpp +++ b/src/common/filesystem/file_rff.cpp @@ -72,7 +72,7 @@ struct RFFLump struct FRFFLump : public FUncompressedLump { virtual FileReader *GetReader(); - virtual int FillCache(); + virtual int FillCache() override; uint32_t IndexNum; diff --git a/src/common/filesystem/file_wad.cpp b/src/common/filesystem/file_wad.cpp index 45e2ec39c..e856212ba 100644 --- a/src/common/filesystem/file_wad.cpp +++ b/src/common/filesystem/file_wad.cpp @@ -100,13 +100,19 @@ public: if(Compressed) { FileReader lzss; - if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, [](const char* err) { I_Error("%s", err); })) + if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, true)) { lzss.Read(Cache, LumpSize); } } else - Owner->Reader.Read(Cache, LumpSize); + { + auto read = Owner->Reader.Read(Cache, LumpSize); + if (read != LumpSize) + { + throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); + } + } RefCount = 1; return 1; diff --git a/src/common/filesystem/file_zip.cpp b/src/common/filesystem/file_zip.cpp index 75ca09da1..355fefa97 100644 --- a/src/common/filesystem/file_zip.cpp +++ b/src/common/filesystem/file_zip.cpp @@ -34,6 +34,7 @@ */ #include +#include #include "file_zip.h" #include "cmdlib.h" @@ -49,7 +50,7 @@ // //========================================================================== -static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) +static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags, bool exceptions) { switch (Method) { @@ -64,7 +65,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L case METHOD_LZMA: { FileReader frz; - if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { I_Error("%s", err); })) + if (frz.OpenDecompressor(Reader, LumpSize, Method, false, exceptions)) { frz.Read(Cache, LumpSize); } @@ -75,7 +76,11 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L case METHOD_IMPLODE: { FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); + if (exploder.Explode((unsigned char*)Cache, LumpSize, Reader, CompressedSize, GPFlags) == -1) + { + // decompression failed so zero the cache. + memset(Cache, 0, LumpSize); + } break; } @@ -96,7 +101,7 @@ bool FCompressedBuffer::Decompress(char *destbuffer) { FileReader mr; mr.OpenMemory(mBuffer, mCompressedSize); - return UncompressZipLump(destbuffer, mr, mMethod, mSize, mCompressedSize, mZipFlags); + return UncompressZipLump(destbuffer, mr, mMethod, mSize, mCompressedSize, mZipFlags, false); } //----------------------------------------------------------------------- @@ -499,16 +504,7 @@ int FZipLump::FillCache() Owner->Reader.Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; - try - { - UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); - } - catch (const CRecoverableError& ) - { - // this cannot propagate the exception but also has no means to handle the error message. Damn... - // At least don't return uninitialized memory here. - memset(Cache, 0, LumpSize); - } + UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags, true); RefCount = 1; return 1; } diff --git a/src/common/filesystem/file_zip.h b/src/common/filesystem/file_zip.h index fc1d9acab..028731f28 100644 --- a/src/common/filesystem/file_zip.h +++ b/src/common/filesystem/file_zip.h @@ -19,7 +19,7 @@ struct FZipLump : public FResourceLump unsigned CRC32; virtual FileReader *GetReader(); - virtual int FillCache(); + virtual int FillCache() override; private: void SetLumpAddress(); diff --git a/src/common/utility/files.cpp b/src/common/filesystem/files.cpp similarity index 100% rename from src/common/utility/files.cpp rename to src/common/filesystem/files.cpp diff --git a/src/common/utility/files.h b/src/common/filesystem/files.h similarity index 91% rename from src/common/utility/files.h rename to src/common/filesystem/files.h index 24d66e1d7..4cfe74382 100644 --- a/src/common/utility/files.h +++ b/src/common/filesystem/files.h @@ -39,11 +39,36 @@ #include #include #include +#include #include #include "basics.h" #include "m_swap.h" #include "tarray.h" +class FileSystemException : public std::exception +{ +protected: + static const int MAX_FSERRORTEXT = 1024; + char m_Message[MAX_FSERRORTEXT]; + +public: + FileSystemException(const char* error, ...) + { + va_list argptr; + va_start(argptr, error); + vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr); + va_end(argptr); + } + FileSystemException(const char* error, va_list argptr) + { + vsnprintf(m_Message, MAX_FSERRORTEXT, error, argptr); + } + char const* what() const noexcept override + { + return m_Message; + } +}; + // Zip compression methods, extended by some internal types to be passed to OpenDecompressor enum { @@ -172,7 +197,7 @@ public: bool OpenMemory(const void *mem, Size length); // read directly from the buffer bool OpenMemoryArray(const void *mem, Size length); // read from a copy of the buffer. bool OpenMemoryArray(std::function&)> getter); // read contents to a buffer and return a reader to it - bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, const std::function& cb); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. + bool OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, bool exceptions = false); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. Size Tell() const { @@ -306,7 +331,7 @@ public: class DecompressorBase : public FileReaderInterface { - std::function ErrorCallback = nullptr; + bool exceptions = false; public: // These do not work but need to be defined to satisfy the FileReaderInterface. // They will just error out when called. @@ -314,11 +339,8 @@ public: long Seek(long offset, int origin) override; char* Gets(char* strbuf, int len) override; void DecompressionError(const char* error, ...) const; - void SetErrorCallback(const std::function& cb) - { - ErrorCallback = cb; - } void SetOwnsReader(); + void EnableExceptions(bool on) { exceptions = on; } protected: FileReader* File = nullptr; diff --git a/src/common/utility/files_decompress.cpp b/src/common/filesystem/files_decompress.cpp similarity index 84% rename from src/common/utility/files_decompress.cpp rename to src/common/filesystem/files_decompress.cpp index 7954b5101..3e636d1bd 100644 --- a/src/common/utility/files_decompress.cpp +++ b/src/common/filesystem/files_decompress.cpp @@ -47,25 +47,22 @@ //========================================================================== // -// I_Error +// DecompressionError // -// Throw an error that will send us to the console if we are far enough -// along in the startup process. +// Allows catching errors from the decompressor. The default is just to +// return failure from the calling function. // //========================================================================== void DecompressorBase::DecompressionError(const char *error, ...) const { - const int MAX_ERRORTEXT = 300; - va_list argptr; - char errortext[MAX_ERRORTEXT]; - - va_start(argptr, error); - vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); - va_end(argptr); - - if (ErrorCallback != nullptr) ErrorCallback(errortext); - else throw std::runtime_error(errortext); + if (exceptions) + { + va_list argptr; + va_start(argptr, error); + throw FileSystemException(error, argptr); + va_end(argptr); + } } long DecompressorBase::Tell () const @@ -103,18 +100,22 @@ class DecompressorZ : public DecompressorBase { enum { BUFF_SIZE = 4096 }; - bool SawEOF; + bool SawEOF = false; z_stream Stream; uint8_t InBuff[BUFF_SIZE]; public: - DecompressorZ (FileReader *file, bool zip, const std::function& cb) - : SawEOF(false) + bool Open (FileReader *file, bool zip) { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + int err; File = file; - SetErrorCallback(cb); FillBuffer (); Stream.zalloc = Z_NULL; @@ -126,7 +127,9 @@ public: if (err != Z_OK) { DecompressionError ("DecompressorZ: inflateInit failed: %s\n", M_ZLibError(err).GetChars()); + return false; } + return true; } ~DecompressorZ () @@ -138,6 +141,12 @@ public: { int err; + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + Stream.next_out = (Bytef *)buffer; Stream.avail_out = len; @@ -153,11 +162,13 @@ public: if (err != Z_OK && err != Z_STREAM_END) { DecompressionError ("Corrupt zlib stream"); + return 0; } if (Stream.avail_out != 0) { DecompressionError ("Ran out of data in zlib stream"); + return 0; } return len - Stream.avail_out; @@ -194,18 +205,22 @@ class DecompressorBZ2 : public DecompressorBase { enum { BUFF_SIZE = 4096 }; - bool SawEOF; + bool SawEOF = false; bz_stream Stream; uint8_t InBuff[BUFF_SIZE]; public: - DecompressorBZ2 (FileReader *file, const std::function& cb) - : SawEOF(false) + bool Open(FileReader *file) { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + int err; File = file; - SetErrorCallback(cb); stupidGlobal = this; FillBuffer (); @@ -218,7 +233,9 @@ public: if (err != BZ_OK) { DecompressionError ("DecompressorBZ2: bzDecompressInit failed: %d\n", err); + return false; } + return true; } ~DecompressorBZ2 () @@ -229,6 +246,12 @@ public: long Read (void *buffer, long len) override { + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + int err; stupidGlobal = this; @@ -247,11 +270,13 @@ public: if (err != BZ_OK && err != BZ_STREAM_END) { DecompressionError ("Corrupt bzip2 stream"); + return 0; } if (Stream.avail_out != 0) { DecompressionError ("Ran out of data in bzip2 stream"); + return 0; } return len - Stream.avail_out; @@ -303,7 +328,7 @@ class DecompressorLZMA : public DecompressorBase { enum { BUFF_SIZE = 4096 }; - bool SawEOF; + bool SawEOF = false; CLzmaDec Stream; size_t Size; size_t InPos, InSize; @@ -312,13 +337,17 @@ class DecompressorLZMA : public DecompressorBase public: - DecompressorLZMA (FileReader *file, size_t uncompressed_size, const std::function& cb) - : SawEOF(false) + bool Open(FileReader *file, size_t uncompressed_size) { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + uint8_t header[4 + LZMA_PROPS_SIZE]; int err; File = file; - SetErrorCallback(cb); Size = uncompressed_size; OutProcessed = 0; @@ -327,11 +356,13 @@ public: if (File->Read(header, sizeof(header)) < (long)sizeof(header)) { DecompressionError("DecompressorLZMA: File too short\n"); + return false; } if (header[2] + header[3] * 256 != LZMA_PROPS_SIZE) { DecompressionError("DecompressorLZMA: LZMA props size is %d (expected %d)\n", header[2] + header[3] * 256, LZMA_PROPS_SIZE); + return false; } FillBuffer(); @@ -342,9 +373,11 @@ public: if (err != SZ_OK) { DecompressionError("DecompressorLZMA: LzmaDec_Allocate failed: %d\n", err); + return false; } LzmaDec_Init(&Stream); + return true; } ~DecompressorLZMA () @@ -354,6 +387,12 @@ public: long Read (void *buffer, long len) override { + if (File == nullptr) + { + DecompressionError("File not open"); + return 0; + } + int err; Byte *next_out = (Byte *)buffer; @@ -372,12 +411,14 @@ public: if (err != SZ_OK) { DecompressionError ("Corrupt LZMA stream"); + return 0; } if (in_processed == 0 && out_processed == 0) { if (status != LZMA_STATUS_FINISHED_WITH_MARK) { DecompressionError ("Corrupt LZMA stream"); + return 0; } } if (InSize == 0 && !SawEOF) @@ -389,11 +430,13 @@ public: if (err != Z_OK && err != Z_STREAM_END) { DecompressionError ("Corrupt LZMA stream"); + return 0; } if (len != 0) { DecompressionError ("Ran out of data in LZMA stream"); + return 0; } return (long)(next_out - (Byte *)buffer); @@ -540,16 +583,22 @@ class DecompressorLZSS : public DecompressorBase } public: - DecompressorLZSS(FileReader *file, const std::function& cb) : SawEOF(false) + bool Open(FileReader *file) { + if (File != nullptr) + { + DecompressionError("File already open"); + return false; + } + File = file; - SetErrorCallback(cb); Stream.State = STREAM_EMPTY; Stream.WindowData = Stream.InternalBuffer = Stream.Window+WINDOW_SIZE; Stream.InternalOut = 0; Stream.AvailIn = 0; FillBuffer(); + return true; } ~DecompressorLZSS() @@ -604,50 +653,91 @@ public: }; -bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, const std::function& cb) +bool FileReader::OpenDecompressor(FileReader &parent, Size length, int method, bool seekable, bool exceptions) { - DecompressorBase *dec = nullptr; - FileReader *p = &parent; - switch (method & ~METHOD_TRANSFEROWNER) + DecompressorBase* dec = nullptr; + try { + FileReader* p = &parent; + switch (method & ~METHOD_TRANSFEROWNER) + { case METHOD_DEFLATE: case METHOD_ZLIB: - dec = new DecompressorZ(p, method == METHOD_DEFLATE, cb); + { + auto idec = new DecompressorZ; + dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p, method == METHOD_DEFLATE)) + { + delete idec; + return false; + } break; - + } case METHOD_BZIP2: - dec = new DecompressorBZ2(p, cb); + { + auto idec = new DecompressorBZ2; + dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p)) + { + delete idec; + return false; + } break; - + } case METHOD_LZMA: - dec = new DecompressorLZMA(p, length, cb); + { + auto idec = new DecompressorLZMA; + dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p, length)) + { + delete idec; + return false; + } break; - + } case METHOD_LZSS: - dec = new DecompressorLZSS(p, cb); + { + auto idec = new DecompressorLZSS; + dec = idec; + idec->EnableExceptions(exceptions); + if (!idec->Open(p)) + { + delete idec; + return false; + } break; + } // todo: METHOD_IMPLODE, METHOD_SHRINK default: return false; - } - if (method & METHOD_TRANSFEROWNER) - { - dec->SetOwnsReader(); - } + } + if (method & METHOD_TRANSFEROWNER) + { + dec->SetOwnsReader(); + } - dec->Length = (long)length; - if (!seekable) - { - Close(); - mReader = dec; - return true; + dec->Length = (long)length; + if (!seekable) + { + Close(); + mReader = dec; + return true; + } + else + { + // todo: create a wrapper. for now this fails + delete dec; + return false; + } } - else + catch (...) { - // todo: create a wrapper. for now this fails - delete dec; - return false; + if (dec) delete dec; + throw; } } diff --git a/src/common/filesystem/filesystem.cpp b/src/common/filesystem/filesystem.cpp index c4bcb64cd..b7c370360 100644 --- a/src/common/filesystem/filesystem.cpp +++ b/src/common/filesystem/filesystem.cpp @@ -569,7 +569,7 @@ int FileSystem::GetNumForName (const char *name, int space) i = CheckNumForName (name, space); if (i == -1) - I_Error ("GetNumForName: %s not found!", name); + throw FileSystemException("GetNumForName: %s not found!", name); return i; } @@ -653,7 +653,7 @@ int FileSystem::GetNumForFullName (const char *name) i = CheckNumForFullName (name); if (i == -1) - I_Error ("GetNumForFullName: %s not found!", name); + throw FileSystemException("GetNumForFullName: %s not found!", name); return i; } @@ -743,7 +743,7 @@ int FileSystem::GetResource (int resid, const char *type, int filenum) const if (i == -1) { - I_Error("GetResource: %d of type %s not found!", resid, type); + throw FileSystemException("GetResource: %d of type %s not found!", resid, type); } return i; } @@ -922,19 +922,19 @@ void FileSystem::InitHashChains (void) LumpShortName& FileSystem::GetShortName(int i) { - if ((unsigned)i >= NumEntries) I_Error("GetShortName: Invalid index"); + if ((unsigned)i >= NumEntries) throw FileSystemException("GetShortName: Invalid index"); return FileInfo[i].shortName; } FString& FileSystem::GetLongName(int i) { - if ((unsigned)i >= NumEntries) I_Error("GetLongName: Invalid index"); + if ((unsigned)i >= NumEntries) throw FileSystemException("GetLongName: Invalid index"); return FileInfo[i].longName; } void FileSystem::RenameFile(int num, const char* newfn) { - if ((unsigned)num >= NumEntries) I_Error("RenameFile: Invalid index"); + if ((unsigned)num >= NumEntries) throw FileSystemException("RenameFile: Invalid index"); FileInfo[num].longName = newfn; // This does not alter the short name - call GetShortname to do that! } @@ -1345,7 +1345,7 @@ TArray FileSystem::GetFileData(int lump, int pad) if (numread != size) { - I_Error("GetFileData: only read %ld of %ld on lump %i\n", + throw FileSystemException("GetFileData: only read %ld of %ld on lump %i\n", numread, size, lump); } if (pad > 0) memset(&data[size], 0, pad); @@ -1367,8 +1367,8 @@ void FileSystem::ReadFile (int lump, void *dest) if (numread != size) { - I_Error ("W_ReadFile: only read %ld of %ld on lump %i\n", - numread, size, lump); + throw FileSystemException("W_ReadFile: only read %ld of %ld on '%s'\n", + numread, size, GetLongName(lump).GetChars()); } } @@ -1399,7 +1399,7 @@ FileReader FileSystem::OpenFileReader(int lump) { if ((unsigned)lump >= (unsigned)FileInfo.Size()) { - I_Error("OpenFileReader: %u >= NumEntries", lump); + throw FileSystemException("OpenFileReader: %u >= NumEntries", lump); } auto rl = FileInfo[lump].lump; @@ -1418,7 +1418,7 @@ FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache) { if ((unsigned)lump >= (unsigned)FileInfo.Size()) { - I_Error("ReopenFileReader: %u >= NumEntries", lump); + throw FileSystemException("ReopenFileReader: %u >= NumEntries", lump); } auto rl = FileInfo[lump].lump; @@ -1619,7 +1619,7 @@ FString::FString (ELumpNum lumpnum) if (numread != size) { - I_Error ("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", + throw FileSystemException("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", numread, size, lumpnum, fileSystem.GetFileFullName((int)lumpnum)); } } diff --git a/src/common/filesystem/resourcefile.cpp b/src/common/filesystem/resourcefile.cpp index f8ae9b09c..3ccf506d9 100644 --- a/src/common/filesystem/resourcefile.cpp +++ b/src/common/filesystem/resourcefile.cpp @@ -193,7 +193,15 @@ void *FResourceLump::Lock() } else if (LumpSize > 0) { - FillCache(); + try + { + FillCache(); + } + catch (const FileSystemException& err) + { + // enrich the message with info about this lump. + throw FileSystemException("%s, file '%s': %s", getName(), Owner->FileName.GetChars(), err.what()); + } } return Cache; } @@ -609,7 +617,13 @@ int FUncompressedLump::FillCache() Owner->Reader.Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; - Owner->Reader.Read(Cache, LumpSize); + + auto read = Owner->Reader.Read(Cache, LumpSize); + if (read != LumpSize) + { + throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); + } + RefCount = 1; return 1; } @@ -672,11 +686,15 @@ int FExternalLump::FillCache() if (f.OpenFile(Filename)) { - f.Read(Cache, LumpSize); + auto read = f.Read(Cache, LumpSize); + if (read != LumpSize) + { + throw FileSystemException("only read %d of %d bytes", (int)read, (int)LumpSize); + } } else { - memset(Cache, 0, LumpSize); + throw FileSystemException("unable to open file"); } RefCount = 1; return 1; diff --git a/src/common/filesystem/resourcefile.h b/src/common/filesystem/resourcefile.h index 65a6a4636..96e0e6ca6 100644 --- a/src/common/filesystem/resourcefile.h +++ b/src/common/filesystem/resourcefile.h @@ -190,7 +190,7 @@ struct FUncompressedLump : public FResourceLump int Position; virtual FileReader *GetReader(); - virtual int FillCache(); + virtual int FillCache() override; virtual int GetFileOffset() { return Position; } }; @@ -213,7 +213,7 @@ struct FExternalLump : public FResourceLump FString Filename; FExternalLump(const char *_filename, int filesize = -1); - virtual int FillCache(); + virtual int FillCache() override; }; diff --git a/src/common/utility/engineerrors.h b/src/common/utility/engineerrors.h index 18fe849bc..a8d439f7a 100644 --- a/src/common/utility/engineerrors.h +++ b/src/common/utility/engineerrors.h @@ -59,13 +59,13 @@ public: strncpy (m_Message, message, MAX_ERRORTEXT-1); m_Message[MAX_ERRORTEXT-1] = '\0'; } - void AppendMessage(const char *message) + void AppendMessage(const char *message) noexcept { size_t len = strlen(m_Message); strncpy(m_Message + len, message, MAX_ERRORTEXT - 1 - len); m_Message[MAX_ERRORTEXT - 1] = '\0'; } - const char *GetMessage (void) const + const char *GetMessage (void) const noexcept { if (m_Message[0] != '\0') return (const char *)m_Message; diff --git a/src/common/utility/utf8.h b/src/common/utility/utf8.h index fe883232b..0b5e4ae0a 100644 --- a/src/common/utility/utf8.h +++ b/src/common/utility/utf8.h @@ -1,5 +1,7 @@ #pragma once +#include + int utf8_encode(int32_t codepoint, uint8_t *buffer, int *size); int utf8_decode(const uint8_t *src, int *size); int GetCharFromString(const uint8_t *&string); diff --git a/src/d_main.cpp b/src/d_main.cpp index 7709c046c..0603283e0 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1233,7 +1233,7 @@ void D_DoomLoop () return; } } - catch (CRecoverableError &error) + catch (const CRecoverableError &error) { if (error.GetMessage ()) { @@ -1241,6 +1241,14 @@ void D_DoomLoop () } D_ErrorCleanup (); } + catch (const FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error. + { + if (error.what()) + { + Printf(PRINT_NONOTIFY | PRINT_BOLD, "\n%s\n", error.what()); + } + D_ErrorCleanup(); + } catch (CVMAbortException &error) { error.MaybePrintMessage(); diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index f57a51b65..1bcd9c34f 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -733,45 +733,36 @@ bool MapLoader::LoadExtendedNodes (FileReader &dalump, uint32_t id) if (compressed) { FileReader zip; - try + if (zip.OpenDecompressor(dalump, -1, METHOD_ZLIB, false, true)) { - if (zip.OpenDecompressor(dalump, -1, METHOD_ZLIB, false, [](const char* err) { I_Error("%s", err); })) - { - LoadZNodes(zip, type); - } - else - { - Printf("Error loading nodes: Corrupt data.\n"); - return false; - } + LoadZNodes(zip, type); + return true; } - catch (const CRecoverableError& err) + else { - Printf("Error loading nodes: %s.\n", err.what()); - - ForceNodeBuild = true; - Level->subsectors.Clear(); - Level->segs.Clear(); - Level->nodes.Clear(); - return false; + Printf("Error loading nodes: Corrupt data.\n"); } } else { LoadZNodes(dalump, type); + return true; } - return true; } catch (CRecoverableError &error) { Printf("Error loading nodes: %s\n", error.GetMessage()); - - ForceNodeBuild = true; - Level->subsectors.Clear(); - Level->segs.Clear(); - Level->nodes.Clear(); - return false; } + catch (FileSystemException& error) + { + Printf("Error loading nodes: %s\n", error.what()); + } + // clean up. + ForceNodeBuild = true; + Level->subsectors.Clear(); + Level->segs.Clear(); + Level->nodes.Clear(); + return false; } @@ -3349,9 +3340,10 @@ void MapLoader::LoadLightmap(MapData *map) return; FileReader fr; - if (!fr.OpenDecompressor(map->Reader(ML_LIGHTMAP), -1, METHOD_ZLIB, false, [](const char* err) { I_Error("%s", err); })) + if (!fr.OpenDecompressor(map->Reader(ML_LIGHTMAP), -1, METHOD_ZLIB, false, false)) return; + int version = fr.ReadInt32(); if (version != 0) {